<commit_before>use std::sync::{ Once, ONCE_INIT };
use std::intrinsics::abort;
use std::{ mem, ptr };
use rand::{ thread_rng, Rng, OsRng };

const GARBAGE_VALUE: u8 = 0xd0;
const CANARY_SIZE: usize = 16;
static ALLOC_INIT: Once = ONCE_INIT;
static mut PAGE_SIZE: usize = 0;
static mut CANARY: [u8; CANARY_SIZE] = [0; CANARY_SIZE];

// -- alloc init --

unsafe fn alloc_init() {
    #[cfg(unix)] {
        let page_size = ::libc::sysconf(::libc::_SC_PAGESIZE);
        if page_size > 0 {
            PAGE_SIZE = page_size as usize;
        }
    }

    #[cfg(windows)] {
        let si = mem::uninitialized();
        ::kernel32::GetSystemInfo(si);
        PAGE_SIZE = ptr::read(si).dwPageSize as usize;
    }

    if PAGE_SIZE < CANARY_SIZE || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    match OsRng::new() {
        Ok(mut rng) => rng.fill_bytes(&mut CANARY),
        Err(_) => thread_rng().fill_bytes(&mut CANARY)
    }
}

// -- aligned alloc / aligned free --

#[cfg(unix)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    let mut memptr = mem::uninitialized();
    match ::libc::posix_memalign(&mut memptr, PAGE_SIZE, size) {
        0 => Some(memptr as *mut T),
        ::libc::EINVAL => panic!("EINVAL: invalid alignmen. {}", PAGE_SIZE),
        ::libc::ENOMEM => None,
        _ => unreachable!()
    }
}

#[cfg(windows)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    Some(::kernel32::VirtualAlloc(
        ptr::null_mut(),
        size as ::winapi::SIZE_T,
        ::winapi::MEM_COMMIT | ::winapi::MEM_RESERVE,
        ::winapi::PAGE_READWRITE
    ) as *mut T)
}

#[cfg(unix)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::libc::free(memptr as *mut ::libc::c_void);
}

#[cfg(windows)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::kernel32::VirtualFree(memptr as ::winapi::LPVOID, 0, ::winapi::MEM_RELEASE);
}

// -- malloc / free --

#[inline]
unsafe fn page_round(size: usize) -> usize {
    let page_mask = PAGE_SIZE - 1;
    (size + page_mask) & (!page_mask)
}

unsafe fn unprotected_ptr_from_user_ptr<T>(memptr: *const T) -> *mut T {
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let page_mask = PAGE_SIZE - 1;
    let unprotected_ptr_u = canary_ptr as usize & !page_mask;
    if unprotected_ptr_u <= PAGE_SIZE * 2 {
        abort();
    }
    unprotected_ptr_u as *mut T
}

unsafe fn _malloc<T>(size: usize) -> Option<*mut T> {
    ALLOC_INIT.call_once(|| alloc_init());

    if size >= ::std::usize::MAX - PAGE_SIZE * 4 {
        return None;
    }
    if PAGE_SIZE <= mem::size_of_val(&CANARY) || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    // aligned alloc ptr
    let size_with_canary = mem::size_of_val(&CANARY) + size;
    let unprotected_size = page_round(size_with_canary);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    let base_ptr = match alloc_aligned(total_size) {
        Some(memptr) => memptr,
        None => return None
    };

    // canary offset
    let unprotected_ptr = base_ptr.offset(PAGE_SIZE as isize * 2);
    ::mprotect(base_ptr.offset(PAGE_SIZE as isize), PAGE_SIZE, ::Prot::NoAccess);
    ptr::copy(
        CANARY.as_ptr(),
        unprotected_ptr.offset(unprotected_size as isize) as *mut u8,
        mem::size_of_val(&CANARY)
    );

    // mprotect ptr
    ::mprotect(unprotected_ptr.offset(unprotected_size as isize), PAGE_SIZE, ::Prot::NoAccess);
    ::mlock(unprotected_ptr, unprotected_size);
    let canary_ptr = unprotected_ptr
        .offset(page_round(size_with_canary) as isize)
        .offset(-(size_with_canary as isize));
    let user_ptr = canary_ptr.offset(mem::size_of_val(&CANARY) as isize);
    ptr::copy(CANARY.as_ptr(), canary_ptr as *mut u8, mem::size_of_val(&CANARY));
    ptr::write(base_ptr as *mut usize, unprotected_size);
    ::mprotect(base_ptr, PAGE_SIZE, ::Prot::ReadOnly);

    debug_assert_eq!(unprotected_ptr_from_user_ptr(user_ptr), unprotected_ptr);

    Some(user_ptr)
}

/// Secure malloc.
pub unsafe fn malloc<T>(size: usize) -> Option<*mut T> {
    _malloc(size)
        .map(|memptr| {
            ::memset(memptr, GARBAGE_VALUE as i32, size);
            memptr
        })
}

/// Alloc array.
///
/// ```
/// use std::{ slice, mem };
/// use memsec::{ allocarray, free, memzero, memset, memcmp };
///
/// let memptr: *mut u8 = unsafe { allocarray(8).unwrap() };
/// let array = unsafe { slice::from_raw_parts_mut(memptr, 8) };
/// assert_eq!(array, [0xd0; 8]);
/// unsafe { memzero(memptr, 8) };
/// assert_eq!(array, [0; 8]);
/// array[0] = 1;
/// assert_eq!(unsafe { memcmp(memptr, [1, 0, 0, 0, 0, 0, 0, 0].as_ptr(), 8) }, 0);
/// unsafe { free(memptr) };
/// ```
pub unsafe fn allocarray<T>(count: usize) -> Option<*mut T> {
    let size = mem::size_of::<T>();
    if count > mem::size_of::<usize>() && size >= ::std::usize::MAX / count {
        None
    } else {
        malloc(count * size)
    }
}

/// Secure free.
pub unsafe fn free<T>(memptr: *mut T) {
    if memptr.is_null() { return () };

    // get unprotected ptr
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let unprotected_ptr = unprotected_ptr_from_user_ptr(memptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    ::mprotect(base_ptr, total_size, ::Prot::ReadWrite);

    // check
    debug_assert_eq!(::memcmp(canary_ptr as *const u8, CANARY.as_ptr(), mem::size_of_val(&CANARY)), 0);
    debug_assert_eq!(::memcmp(
        unprotected_ptr.offset(unprotected_size as isize) as *const u8,
        CANARY.as_ptr(),
        mem::size_of_val(&CANARY)
    ), 0);

    // free
    ::munlock(unprotected_ptr, unprotected_size);
    free_aligned(base_ptr);
}

// -- unprotected mprotect --

/// Secure mprotect.
pub unsafe fn unprotected_mprotect<T>(ptr: *mut T, prot: ::Prot) -> bool {
    let unprotected_ptr = unprotected_ptr_from_user_ptr(ptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    ::mprotect(unprotected_ptr, unprotected_size, prot)
}

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

    #[should_panic]
    #[test]
    fn mprotect_test() {
        use nix::sys::signal;

        super::ALLOC_INIT.call_once(|| unsafe { super::alloc_init() });

        extern fn sigsegv(_: i32) { panic!() }
        let sigaction = signal::SigAction::new(
            signal::SigHandler::Handler(sigsegv),
            signal::SA_SIGINFO,
            signal::SigSet::empty(),
        );
        unsafe { signal::sigaction(signal::SIGSEGV, &sigaction).ok() };

        let x: *mut u8 = unsafe { super::alloc_aligned(16 * mem::size_of::<u8>()).unwrap() };
        unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::NoAccess) };

        unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) }; // SIGSEGV!
    }
}
<commit_msg>add test alloc_free_aligned<commit_after>use std::sync::{ Once, ONCE_INIT };
use std::intrinsics::abort;
use std::{ mem, ptr };
use rand::{ thread_rng, Rng, OsRng };

const GARBAGE_VALUE: u8 = 0xd0;
const CANARY_SIZE: usize = 16;
static ALLOC_INIT: Once = ONCE_INIT;
static mut PAGE_SIZE: usize = 0;
static mut CANARY: [u8; CANARY_SIZE] = [0; CANARY_SIZE];

// -- alloc init --

unsafe fn alloc_init() {
    #[cfg(unix)] {
        let page_size = ::libc::sysconf(::libc::_SC_PAGESIZE);
        if page_size > 0 {
            PAGE_SIZE = page_size as usize;
        }
    }

    #[cfg(windows)] {
        let si = mem::uninitialized();
        ::kernel32::GetSystemInfo(si);
        PAGE_SIZE = ptr::read(si).dwPageSize as usize;
    }

    if PAGE_SIZE < CANARY_SIZE || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    match OsRng::new() {
        Ok(mut rng) => rng.fill_bytes(&mut CANARY),
        Err(_) => thread_rng().fill_bytes(&mut CANARY)
    }
}

// -- aligned alloc / aligned free --

#[cfg(unix)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    let mut memptr = mem::uninitialized();
    match ::libc::posix_memalign(&mut memptr, PAGE_SIZE, size) {
        0 => Some(memptr as *mut T),
        ::libc::EINVAL => panic!("EINVAL: invalid alignmen. {}", PAGE_SIZE),
        ::libc::ENOMEM => None,
        _ => unreachable!()
    }
}

#[cfg(windows)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    Some(::kernel32::VirtualAlloc(
        ptr::null_mut(),
        size as ::winapi::SIZE_T,
        ::winapi::MEM_COMMIT | ::winapi::MEM_RESERVE,
        ::winapi::PAGE_READWRITE
    ) as *mut T)
}

#[cfg(unix)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::libc::free(memptr as *mut ::libc::c_void);
}

#[cfg(windows)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::kernel32::VirtualFree(memptr as ::winapi::LPVOID, 0, ::winapi::MEM_RELEASE);
}

// -- malloc / free --

#[inline]
unsafe fn page_round(size: usize) -> usize {
    let page_mask = PAGE_SIZE - 1;
    (size + page_mask) & (!page_mask)
}

unsafe fn unprotected_ptr_from_user_ptr<T>(memptr: *const T) -> *mut T {
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let page_mask = PAGE_SIZE - 1;
    let unprotected_ptr_u = canary_ptr as usize & !page_mask;
    if unprotected_ptr_u <= PAGE_SIZE * 2 {
        abort();
    }
    unprotected_ptr_u as *mut T
}

unsafe fn _malloc<T>(size: usize) -> Option<*mut T> {
    ALLOC_INIT.call_once(|| alloc_init());

    if size >= ::std::usize::MAX - PAGE_SIZE * 4 {
        return None;
    }
    if PAGE_SIZE <= mem::size_of_val(&CANARY) || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    // aligned alloc ptr
    let size_with_canary = mem::size_of_val(&CANARY) + size;
    let unprotected_size = page_round(size_with_canary);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    let base_ptr = match alloc_aligned(total_size) {
        Some(memptr) => memptr,
        None => return None
    };

    // canary offset
    let unprotected_ptr = base_ptr.offset(PAGE_SIZE as isize * 2);
    ::mprotect(base_ptr.offset(PAGE_SIZE as isize), PAGE_SIZE, ::Prot::NoAccess);
    ptr::copy(
        CANARY.as_ptr(),
        unprotected_ptr.offset(unprotected_size as isize) as *mut u8,
        mem::size_of_val(&CANARY)
    );

    // mprotect ptr
    ::mprotect(unprotected_ptr.offset(unprotected_size as isize), PAGE_SIZE, ::Prot::NoAccess);
    ::mlock(unprotected_ptr, unprotected_size);
    let canary_ptr = unprotected_ptr
        .offset(page_round(size_with_canary) as isize)
        .offset(-(size_with_canary as isize));
    let user_ptr = canary_ptr.offset(mem::size_of_val(&CANARY) as isize);
    ptr::copy(CANARY.as_ptr(), canary_ptr as *mut u8, mem::size_of_val(&CANARY));
    ptr::write(base_ptr as *mut usize, unprotected_size);
    ::mprotect(base_ptr, PAGE_SIZE, ::Prot::ReadOnly);

    debug_assert_eq!(unprotected_ptr_from_user_ptr(user_ptr), unprotected_ptr);

    Some(user_ptr)
}

/// Secure malloc.
pub unsafe fn malloc<T>(size: usize) -> Option<*mut T> {
    _malloc(size)
        .map(|memptr| {
            ::memset(memptr, GARBAGE_VALUE as i32, size);
            memptr
        })
}

/// Alloc array.
///
/// ```
/// use std::{ slice, mem };
/// use memsec::{ allocarray, free, memzero, memset, memcmp };
///
/// let memptr: *mut u8 = unsafe { allocarray(8).unwrap() };
/// let array = unsafe { slice::from_raw_parts_mut(memptr, 8) };
/// assert_eq!(array, [0xd0; 8]);
/// unsafe { memzero(memptr, 8) };
/// assert_eq!(array, [0; 8]);
/// array[0] = 1;
/// assert_eq!(unsafe { memcmp(memptr, [1, 0, 0, 0, 0, 0, 0, 0].as_ptr(), 8) }, 0);
/// unsafe { free(memptr) };
/// ```
pub unsafe fn allocarray<T>(count: usize) -> Option<*mut T> {
    let size = mem::size_of::<T>();
    if count > mem::size_of::<usize>() && size >= ::std::usize::MAX / count {
        None
    } else {
        malloc(count * size)
    }
}

/// Secure free.
pub unsafe fn free<T>(memptr: *mut T) {
    if memptr.is_null() { return () };

    // get unprotected ptr
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let unprotected_ptr = unprotected_ptr_from_user_ptr(memptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    ::mprotect(base_ptr, total_size, ::Prot::ReadWrite);

    // check
    debug_assert_eq!(::memcmp(canary_ptr as *const u8, CANARY.as_ptr(), mem::size_of_val(&CANARY)), 0);
    debug_assert_eq!(::memcmp(
        unprotected_ptr.offset(unprotected_size as isize) as *const u8,
        CANARY.as_ptr(),
        mem::size_of_val(&CANARY)
    ), 0);

    // free
    ::munlock(unprotected_ptr, unprotected_size);
    free_aligned(base_ptr);
}

// -- unprotected mprotect --

/// Secure mprotect.
pub unsafe fn unprotected_mprotect<T>(ptr: *mut T, prot: ::Prot) -> bool {
    let unprotected_ptr = unprotected_ptr_from_user_ptr(ptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    ::mprotect(unprotected_ptr, unprotected_size, prot)
}

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

    #[should_panic]
    #[test]
    fn mprotect_test() {
        use nix::sys::signal;

        super::ALLOC_INIT.call_once(|| unsafe { super::alloc_init() });

        extern fn sigsegv(_: i32) { panic!() }
        let sigaction = signal::SigAction::new(
            signal::SigHandler::Handler(sigsegv),
            signal::SA_SIGINFO,
            signal::SigSet::empty(),
        );
        unsafe { signal::sigaction(signal::SIGSEGV, &sigaction).ok() };

        let x: *mut u8 = unsafe { super::alloc_aligned(16 * mem::size_of::<u8>()).unwrap() };
        unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::NoAccess) };

        unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) }; // SIGSEGV!
    }
}

#[test]
fn alloc_free_aligned() {
    ALLOC_INIT.call_once(|| unsafe { alloc_init() });

    let x: *mut u8 = unsafe { alloc_aligned(16 * mem::size_of::<u8>()).unwrap() };
    unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) };
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::ReadOnly) });
    assert_eq!(unsafe { ::memcmp(x, [0; 16].as_ptr(), 16 * mem::size_of::<u8>()) }, 0);
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::NoAccess) });
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::ReadWrite) });
    unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) };
    unsafe { free_aligned(x) };
}
<|endoftext|>


<commit_before>use crate::{WriteableKey, KeyNameInvalidError};

/// Use the `KeyBuilder` to easily build a key with many meta values.
/// # Example
/// ```
/// # use elektra::{KeyBuilder,StringKey,WriteableKey,ReadableKey};
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let key: StringKey =
///     KeyBuilder::new("user/test/newkey")?
///         .value("0xff")
///         .meta("type", "octet")?
///         .meta("unit/base", "hex")?
///         .build();
/// assert_eq!(key.name(), "user/test/newkey");
/// assert_eq!(key.value(), "0xff");
/// assert_eq!(key.meta("type")?.value(), "octet");
/// assert_eq!(key.meta("unit/base")?.value(), "hex");
/// #
/// #     Ok(())
/// # }
/// ```
/// In a `keyset!` definition, it is useful to use the "turbofish" syntax for type annotation.
/// ```
/// # use elektra::{KeyBuilder,keyset,KeySet,StringKey,WriteableKey,ReadableKey};
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let ks = keyset![
///     KeyBuilder::<StringKey>::new("user/test/newkey")?
///         .value("0xff")
///         .build()
/// ];
/// # assert_eq!(ks.head().unwrap().value(), "0xff");
/// # Ok(())
/// # }
/// ```
pub struct KeyBuilder<T: WriteableKey> {
    key: T,
}

impl<T: WriteableKey> KeyBuilder<T> {
    /// Construct a new key with a name.
    /// Returns a `KeyNameInvalidError` if the name is invalid.
    ///
    /// # Panics
    /// Panics if an allocation error (out of memory) occurs in the C-constructor.
    pub fn new(name: &str) -> Result<Self, KeyNameInvalidError> {
        let key = T::new(name)?;
        Ok(KeyBuilder { key })
    }
    /// Construct a new nameless key.
    ///
    /// # Panics
    /// Panics if an allocation error (out of memory) occurs in the C-constructor.
    pub fn new_empty() -> Self {
        let key = T::new_empty();
        KeyBuilder { key }
    }

    /// Set the name of a key. Must adhere to the rules for keynames otherwise an `KeyNameInvalidError` is returned.
    /// Returns the size in bytes of this new key name including the ending NUL.
    ///
    /// # Panics
    /// Panics if the provided string contains interior nul bytes.
    pub fn name(mut self, name: &str) -> Result<Self, KeyNameInvalidError> {
        self.key.set_name(name)?;
        Ok(self)
    }

    /// Set the value of the key.
    pub fn value(mut self, key_value: T::SetValue) -> Self {
        self.key.set_value(key_value);
        self
    }

    /// Set a new meta-information.
    /// Returns a `KeyNameInvalidError` if the name is invalid.
    ///
    /// # Panics
    /// Panics if any of the provided strings contains interior nul bytes.
    pub fn meta(mut self, metaname: &str, metavalue: &str) -> Result<Self, KeyNameInvalidError> {
        self.key.set_meta(metaname, metavalue)?;
        Ok(self)
    }

    /// Consumes the KeyBuilder and returns the key.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{KeyBuilder,StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key: StringKey = KeyBuilder::new("user/test/newkey")?
    ///     .value("key_value")
    ///     .build();
    /// assert_eq!(key.name(), "user/test/newkey");
    /// assert_eq!(key.value(), "key_value");
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    pub fn build(self) -> T {
        self.key
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{BinaryKey, ReadableKey, StringKey};

    #[test]
    fn can_build_string_key() -> Result<(), KeyNameInvalidError> {
        let name = "user/test/newkey";
        let val = "key_value";
        let key: StringKey = KeyBuilder::new(name)?.value(val).build();
        assert_eq!(key.name(), name);
        assert_eq!(key.value(), val);
        Ok(())
    }

    #[test]
    fn can_build_binary_key() -> Result<(), KeyNameInvalidError> {
        let name = "user/test/binarykey";
        let overwrite = "overwrite me";
        let val = "😎";
        let key: BinaryKey = KeyBuilder::new(name)?
            .value(overwrite.as_bytes())
            .value(val.as_bytes())
            .build();
        assert_eq!(key.name(), name);
        assert_eq!(key.value(), val.to_owned().into_bytes());
        Ok(())
    }

    #[test]
    fn can_build_key_with_meta() -> Result<(), KeyNameInvalidError> {
        let name = "user/test/metatest";
        let key: StringKey = KeyBuilder::new(name)?
            .meta("metaname", "metavalue")?
            .meta("OWNER", "me")?
            .build();
        assert_eq!(key.meta("OWNER").unwrap().value(), "me");
        assert_eq!(key.meta("metaname").unwrap().value(), "metavalue");
        Ok(())
    }

}
<commit_msg>rust: Move keybuilder oneliner into module doc<commit_after>//! The `KeyBuilder` can easily build keys with many meta values.
//!
//! # Examples
//! ```
//! # use elektra::{KeyBuilder,StringKey,WriteableKey,ReadableKey};
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let key: StringKey =
//!     KeyBuilder::new("user/test/newkey")?
//!         .value("0xff")
//!         .meta("type", "octet")?
//!         .meta("unit/base", "hex")?
//!         .build();
//! assert_eq!(key.name(), "user/test/newkey");
//! assert_eq!(key.value(), "0xff");
//! assert_eq!(key.meta("type")?.value(), "octet");
//! assert_eq!(key.meta("unit/base")?.value(), "hex");
//! #
//! #     Ok(())
//! # }
//! ```
//! In a `keyset!` definition, it is useful to use the "turbofish" syntax for type annotation.
//! ```
//! # use elektra::{KeyBuilder,keyset,KeySet,StringKey,WriteableKey,ReadableKey};
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let ks = keyset![
//!     KeyBuilder::<StringKey>::new("user/test/newkey")?
//!         .value("0xff")
//!         .build()
//! ];
//! # assert_eq!(ks.head().unwrap().value(), "0xff");
//! # Ok(())
//! # }
//! ```

use crate::{WriteableKey, KeyNameInvalidError};
pub struct KeyBuilder<T: WriteableKey> {
    key: T,
}

impl<T: WriteableKey> KeyBuilder<T> {
    /// Construct a new key with a name.
    /// Returns a `KeyNameInvalidError` if the name is invalid.
    ///
    /// # Panics
    /// Panics if an allocation error (out of memory) occurs in the C-constructor.
    pub fn new(name: &str) -> Result<Self, KeyNameInvalidError> {
        let key = T::new(name)?;
        Ok(KeyBuilder { key })
    }
    /// Construct a new nameless key.
    ///
    /// # Panics
    /// Panics if an allocation error (out of memory) occurs in the C-constructor.
    pub fn new_empty() -> Self {
        let key = T::new_empty();
        KeyBuilder { key }
    }

    /// Set the name of a key. Must adhere to the rules for keynames otherwise an `KeyNameInvalidError` is returned.
    /// Returns the size in bytes of this new key name including the ending NUL.
    ///
    /// # Panics
    /// Panics if the provided string contains interior nul bytes.
    pub fn name(mut self, name: &str) -> Result<Self, KeyNameInvalidError> {
        self.key.set_name(name)?;
        Ok(self)
    }

    /// Set the value of the key.
    pub fn value(mut self, key_value: T::SetValue) -> Self {
        self.key.set_value(key_value);
        self
    }

    /// Set a new meta-information.
    /// Returns a `KeyNameInvalidError` if the name is invalid.
    ///
    /// # Panics
    /// Panics if any of the provided strings contains interior nul bytes.
    pub fn meta(mut self, metaname: &str, metavalue: &str) -> Result<Self, KeyNameInvalidError> {
        self.key.set_meta(metaname, metavalue)?;
        Ok(self)
    }

    /// Consumes the KeyBuilder and returns the key.
    ///
    /// # Examples
    /// ```
    /// # use elektra::{KeyBuilder,StringKey,WriteableKey,ReadableKey};
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// let key: StringKey = KeyBuilder::new("user/test/newkey")?
    ///     .value("key_value")
    ///     .build();
    /// assert_eq!(key.name(), "user/test/newkey");
    /// assert_eq!(key.value(), "key_value");
    /// #
    /// #     Ok(())
    /// # }
    /// ```
    pub fn build(self) -> T {
        self.key
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{BinaryKey, ReadableKey, StringKey};

    #[test]
    fn can_build_string_key() -> Result<(), KeyNameInvalidError> {
        let name = "user/test/newkey";
        let val = "key_value";
        let key: StringKey = KeyBuilder::new(name)?.value(val).build();
        assert_eq!(key.name(), name);
        assert_eq!(key.value(), val);
        Ok(())
    }

    #[test]
    fn can_build_binary_key() -> Result<(), KeyNameInvalidError> {
        let name = "user/test/binarykey";
        let overwrite = "overwrite me";
        let val = "😎";
        let key: BinaryKey = KeyBuilder::new(name)?
            .value(overwrite.as_bytes())
            .value(val.as_bytes())
            .build();
        assert_eq!(key.name(), name);
        assert_eq!(key.value(), val.to_owned().into_bytes());
        Ok(())
    }

    #[test]
    fn can_build_key_with_meta() -> Result<(), KeyNameInvalidError> {
        let name = "user/test/metatest";
        let key: StringKey = KeyBuilder::new(name)?
            .meta("metaname", "metavalue")?
            .meta("OWNER", "me")?
            .build();
        assert_eq!(key.meta("OWNER").unwrap().value(), "me");
        assert_eq!(key.meta("metaname").unwrap().value(), "metavalue");
        Ok(())
    }

}
<|endoftext|>


<commit_before>use futures::task::Poll;
use futures::Future;
use log_ndc::Ndc;
use std::pin::Pin;
use std::task::Context;

pub(crate) fn log_ndc_future<N, F>(ndc: N, f: F) -> LogNdcFuture<N, F>
where
    N: Into<Ndc> + Clone,
    F: Future,
{
    LogNdcFuture { ndc, f }
}

pub(crate) struct LogNdcFuture<N, F>
where
    N: Into<Ndc>,
    F: Future,
{
    ndc: N,
    f: F,
}

impl<N, F> Future for LogNdcFuture<N, F>
where
    N: Into<Ndc> + Clone,
    F: Future,
{
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
        let _guard = log_ndc::push(self.ndc.clone().into());
        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().f) }.poll(cx)
    }
}
<commit_msg>Slightly different NDC interface<commit_after>use futures::task::Poll;
use futures::Future;
use log_ndc::Ndc;
use std::pin::Pin;
use std::sync::Arc;
use std::task::Context;

pub(crate) trait ToNdc {
    fn to_ndc(&self) -> Ndc;
}

impl ToNdc for Arc<String> {
    fn to_ndc(&self) -> Ndc {
        Ndc::Arc(self.clone())
    }
}

pub(crate) fn log_ndc_future<N, F>(ndc: N, f: F) -> LogNdcFuture<N, F>
where
    N: ToNdc,
    F: Future,
{
    LogNdcFuture { ndc, f }
}

pub(crate) struct LogNdcFuture<N, F>
where
    N: ToNdc,
    F: Future,
{
    ndc: N,
    f: F,
}

impl<N, F> Future for LogNdcFuture<N, F>
where
    N: ToNdc,
    F: Future,
{
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
        let _guard = log_ndc::push(self.ndc.to_ndc());
        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().f) }.poll(cx)
    }
}
<|endoftext|>


<commit_before>#![feature(if_let)]
use std::io;
use std::io::fs;
use std::io::fs::PathExtensions;
use std::io::process::{ProcessExit, Command};
use std::path::Path;
use std::os;

fn main() {

	io::println("Searching for LibJIT");
	let ref out_path = Path::new(os::getenv("OUT_DIR").unwrap());
	let ref lib_path = Path::new("/usr/lib/libjit.so");
	let ref eventual_lib_path = Path::new("native/jit/.libs/libjit.so");
	let ref dest_path = out_path.join("libjit.so");
	let ref submod_path = Path::new("native");
	if lib_path.exists() {
		fs::copy(lib_path, dest_path).unwrap();
	} else if !dest_path.exists() {
		if !eventual_lib_path.exists() {
			io::println("No LibJIT found in /usr/lib/ so updating LibJIT");
			if !submod_path.exists() {
				io::println!("Initialising submodule");
				run(Command::new("git").arg("submodule").arg("init"));
			}
			run(Command::new("git").arg("submodule").arg("update"));
			let old_cwd = os::getcwd();
			os::change_dir(submod_path);
			io::println("Configuring LibJIT");
			run(Command::new("sh").arg("auto_gen.sh"));
			run_cmd("./configure");

			io::println("Building LibJIT");
			run_cmd("make");
			os::change_dir(&old_cwd);
		}
		fs::copy(eventual_lib_path, dest_path).unwrap();
	}
	println!("cargo:rustc-flags=-L {}", out_path.display());
}
fn run_cmd(command: &str) {
	run(&mut Command::new(command))
}
fn run(command: &mut Command) {
	let process = command.output().unwrap();
	if !process.status.success() {
		panic!("Command '{}' failed with output: \n{}\n{}", command, String::from_utf8_lossy(process.output[]), String::from_utf8_lossy(process.error[]));
	}
}<commit_msg>Remove evil exclamation mark<commit_after>#![feature(if_let)]
use std::io;
use std::io::fs;
use std::io::fs::PathExtensions;
use std::io::process::{ProcessExit, Command};
use std::path::Path;
use std::os;

fn main() {

	io::println("Searching for LibJIT");
	let ref out_path = Path::new(os::getenv("OUT_DIR").unwrap());
	let ref lib_path = Path::new("/usr/lib/libjit.so");
	let ref eventual_lib_path = Path::new("native/jit/.libs/libjit.so");
	let ref dest_path = out_path.join("libjit.so");
	let ref submod_path = Path::new("native");
	if lib_path.exists() {
		fs::copy(lib_path, dest_path).unwrap();
	} else if !dest_path.exists() {
		if !eventual_lib_path.exists() {
			io::println("No LibJIT found in /usr/lib/ so updating LibJIT");
			if !submod_path.exists() {
				io::println("Initialising submodule");
				run(Command::new("git").arg("submodule").arg("init"));
			}
			run(Command::new("git").arg("submodule").arg("update"));
			let old_cwd = os::getcwd();
			os::change_dir(submod_path);
			io::println("Configuring LibJIT");
			run(Command::new("sh").arg("auto_gen.sh"));
			run_cmd("./configure");

			io::println("Building LibJIT");
			run_cmd("make");
			os::change_dir(&old_cwd);
		}
		fs::copy(eventual_lib_path, dest_path).unwrap();
	}
	println!("cargo:rustc-flags=-L {}", out_path.display());
}
fn run_cmd(command: &str) {
	run(&mut Command::new(command))
}
fn run(command: &mut Command) {
	let process = command.output().unwrap();
	if !process.status.success() {
		panic!("Command '{}' failed with output: \n{}\n{}", command, String::from_utf8_lossy(process.output[]), String::from_utf8_lossy(process.error[]));
	}
}<|endoftext|>


<commit_before>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib_ffi;
use std::borrow::Borrow;
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::slice;
use translate::*;

glib_wrapper! {
    /// A shared immutable byte slice (the equivalent of `Rc<[u8]>`).
    ///
    /// `From` implementations that take references (e.g. `&[u8]`) copy the
    /// data. The `from_static` constructor avoids copying static data.
    ///
    /// ```
    /// use glib::Bytes;
    ///
    /// let v = vec![1, 2, 3];
    /// let b = Bytes::from(&v);
    /// assert_eq!(v, b);
    ///
    /// let s = b"xyz";
    /// let b = Bytes::from_static(s);
    /// assert_eq!(&s[..], b);
    /// ```
    pub struct Bytes(Shared<glib_ffi::GBytes>);

    match fn {
        ref => |ptr| glib_ffi::g_bytes_ref(ptr),
        unref => |ptr| glib_ffi::g_bytes_unref(ptr),
    }
}

impl Bytes {
    fn new<T: ?Sized + Borrow<[u8]>>(data: &T) -> Bytes {
        let data = data.borrow();
        unsafe { from_glib_full(glib_ffi::g_bytes_new(data.as_ptr() as *const _, data.len())) }
    }

    ///
    pub fn from_static<T: ?Sized + Borrow<[u8]>>(data: &'static T) -> Bytes {
        let data = data.borrow();
        unsafe {
            from_glib_full(glib_ffi::g_bytes_new_static(data.as_ptr() as *const _, data.len()))
        }
    }
}

unsafe impl Send for Bytes { }
unsafe impl Sync for Bytes { }

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes {
    fn from(value: &'a T) -> Bytes {
        Bytes::new(value)
    }
}

impl fmt::Debug for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Bytes")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

impl Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut len = 0;
            let ptr = glib_ffi::g_bytes_get_data(self.to_glib_none().0, &mut len);
            debug_assert!(!ptr.is_null() || len == 0);
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

impl PartialEq for Bytes {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_bytes_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Bytes { }

impl PartialOrd for Bytes {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.partial_cmp(&0)
        }
    }
}

impl Ord for Bytes {
    fn cmp(&self, other: &Self) -> Ordering {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.cmp(&0)
        }
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    }
}

impl_cmp!(Bytes, [u8]);
impl_cmp!(Bytes, &'a [u8]);
impl_cmp!(&'a Bytes, [u8]);
impl_cmp!(Bytes, Vec<u8>);
impl_cmp!(&'a Bytes, Vec<u8>);

impl Hash for Bytes {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(self, state)
    }
}

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

    #[test]
    fn eq() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a1 = Bytes::from(abc);
        let a2 = Bytes::from(abc);
        let d = Bytes::from(def);
        assert_eq!(a1, a2);
        assert_eq!(def, d);
        assert!(a1 != d);
        assert!(a1 != def);
    }

    #[test]
    fn ord() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a = Bytes::from(abc);
        let d = Bytes::from(def);
        assert!(a < d);
        assert!(a < def);
        assert!(abc < d);
        assert!(d > a);
        assert!(d > abc);
        assert!(def > a);
    }

    #[test]
    fn hash() {
        let b1 = Bytes::from(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        let b3 = Bytes::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }

    #[test]
    fn from_static() {
        let b1 = Bytes::from_static(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        assert_eq!(b1, b2);
    }
}
<commit_msg>Simplify Bytes constructor signatures to play nice with fixed-sized arrays<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib_ffi;
use std::borrow::Borrow;
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::slice;
use translate::*;

glib_wrapper! {
    /// A shared immutable byte slice (the equivalent of `Rc<[u8]>`).
    ///
    /// `From` implementations that take references (e.g. `&[u8]`) copy the
    /// data. The `from_static` constructor avoids copying static data.
    ///
    /// ```
    /// use glib::Bytes;
    ///
    /// let v = vec![1, 2, 3];
    /// let b = Bytes::from(&v);
    /// assert_eq!(v, b);
    ///
    /// let s = b"xyz";
    /// let b = Bytes::from_static(s);
    /// assert_eq!(&s[..], b);
    /// ```
    pub struct Bytes(Shared<glib_ffi::GBytes>);

    match fn {
        ref => |ptr| glib_ffi::g_bytes_ref(ptr),
        unref => |ptr| glib_ffi::g_bytes_unref(ptr),
    }
}

impl Bytes {
    /// Copies `data` into a new shared slice.
    fn new(data: &[u8]) -> Bytes {
        unsafe { from_glib_full(glib_ffi::g_bytes_new(data.as_ptr() as *const _, data.len())) }
    }

    /// Creates a view into static `data` without copying.
    pub fn from_static(data: &'static [u8]) -> Bytes {
        unsafe {
            from_glib_full(glib_ffi::g_bytes_new_static(data.as_ptr() as *const _, data.len()))
        }
    }
}

unsafe impl Send for Bytes { }
unsafe impl Sync for Bytes { }

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes {
    fn from(value: &'a T) -> Bytes {
        Bytes::new(value.borrow())
    }
}

impl fmt::Debug for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Bytes")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

impl Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut len = 0;
            let ptr = glib_ffi::g_bytes_get_data(self.to_glib_none().0, &mut len);
            debug_assert!(!ptr.is_null() || len == 0);
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

impl PartialEq for Bytes {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_bytes_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Bytes { }

impl PartialOrd for Bytes {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.partial_cmp(&0)
        }
    }
}

impl Ord for Bytes {
    fn cmp(&self, other: &Self) -> Ordering {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.cmp(&0)
        }
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    }
}

impl_cmp!(Bytes, [u8]);
impl_cmp!(Bytes, &'a [u8]);
impl_cmp!(&'a Bytes, [u8]);
impl_cmp!(Bytes, Vec<u8>);
impl_cmp!(&'a Bytes, Vec<u8>);

impl Hash for Bytes {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(self, state)
    }
}

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

    #[test]
    fn eq() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a1 = Bytes::from(abc);
        let a2 = Bytes::from(abc);
        let d = Bytes::from(def);
        assert_eq!(a1, a2);
        assert_eq!(def, d);
        assert!(a1 != d);
        assert!(a1 != def);
    }

    #[test]
    fn ord() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a = Bytes::from(abc);
        let d = Bytes::from(def);
        assert!(a < d);
        assert!(a < def);
        assert!(abc < d);
        assert!(d > a);
        assert!(d > abc);
        assert!(def > a);
    }

    #[test]
    fn hash() {
        let b1 = Bytes::from(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        let b3 = Bytes::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }

    #[test]
    fn from_static() {
        let b1 = Bytes::from_static(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        assert_eq!(b1, b2);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;

use regex::bytes::Regex;

use crate::common::Lines;
use crate::Solution;

#[derive(Clone, Debug)]
struct Tile {
    grid: Vec<Vec<bool>>,
    id: u64,
    // NESW order
    sides: [Vec<bool>; 4],
    rotations: u8,
    flipped: bool,
}

impl Tile {
    /// Rotate the slice once to the left. Affects
    fn rotate(&mut self) {
        self.rotations = (self.rotations + 1) % 4;
        self.sides.rotate_right(1);
        self.sides[0].reverse();
        self.sides[2].reverse();
    }

    /// Horizontally flip the tile
    fn flip(&mut self) {
        debug_assert!(!self.flipped);
        self.flipped = !self.flipped;
        self.sides[0].reverse();
        self.sides[2].reverse();
        self.sides.swap(1, 3);
    }

    fn len(&self) -> usize {
        self.grid.len() - 2
    }
}

fn read_input(input: &mut dyn Read) -> HashMap<u64, Tile> {
    let mut tiles = HashMap::new();
    let mut lines = Lines::new(input);

    while let Some(line) = lines.next() {
        let id = line[5..(line.len() - 1)].parse().unwrap();
        drop(line);

        let mut grid: Vec<Vec<_>> = Vec::new();

        while let Some(line) = lines.next() {
            if line.is_empty() {
                break;
            }

            grid.push(line.chars().map(|c| c == '#').collect());
        }

        let sides = [
            grid[0].clone(),
            grid.iter().map(|v| *v.last().unwrap()).collect(),
            grid.last().cloned().unwrap(),
            grid.iter().map(|v| v[0]).collect(),
        ];

        let tile = Tile {
            grid,
            sides,
            id,
            rotations: 0,
            flipped: false,
        };

        tiles.insert(id, tile);
    }

    tiles
}

fn compute_matching<'a>(tiles: impl IntoIterator<Item = &'a Tile>) -> HashMap<Vec<bool>, Vec<u64>> {
    let mut matching: HashMap<Vec<_>, Vec<u64>> = HashMap::new();

    for tile in tiles {
        for side in &tile.sides {
            let neighbours = matching.entry(side.clone()).or_default();

            if !neighbours.contains(&tile.id) {
                neighbours.push(tile.id);
            }

            let mut rev = side.clone();
            rev.reverse();

            let neighbours = matching.entry(rev).or_default();

            if !neighbours.contains(&tile.id) {
                neighbours.push(tile.id);
            }
        }
    }

    // Check if my tile assumption is violated
    debug_assert!(matching.values().map(Vec::len).max().unwrap_or(0) <= 2);

    matching
}

fn compute_neighbours<'a>(
    cliques: impl IntoIterator<Item = &'a Vec<u64>>,
) -> HashMap<u64, Vec<u64>> {
    let mut neighbours: HashMap<u64, Vec<u64>> = HashMap::new();

    for clique in cliques {
        for &a in clique {
            let related = neighbours.entry(a).or_default();

            for &b in clique {
                if a != b && !related.contains(&b) {
                    related.push(b);
                }
            }
        }
    }

    neighbours
}

fn rev_eq(a: &[bool], b: &[bool]) -> bool {
    a.iter().zip(b.iter().rev()).all(|(&a, &b)| a == b)
}

fn complete_row(
    mut first: u64,
    neighbours: &HashMap<u64, Vec<u64>>,
    tiles: &mut HashMap<u64, Tile>,
    used_tiles: &mut HashSet<u64>,
) -> Vec<u64> {
    let mut row = vec![first];
    used_tiles.insert(first);

    loop {
        let last = first;
        let mut next = None;

        for n in &neighbours[&last] {
            if used_tiles.contains(n) {
                continue;
            }

            for _ in 0..4 {
                if &tiles[&last].sides[1] == &tiles[n].sides[3] {
                    break;
                } else if rev_eq(&tiles[&last].sides[1], &tiles[n].sides[3]) {
                    let tile = tiles.get_mut(n).unwrap();

                    // Vertical flip == horizontal flip + 180
                    tile.rotate();
                    tile.rotate();
                    tile.flip();
                    break;
                } else {
                    tiles.get_mut(&n).unwrap().rotate();
                }
            }

            if &tiles[&last].sides[1] == &tiles[n].sides[3] {
                // This tile matches, add it
                next = Some(*n);
                break;
            }
        }

        if let Some(next) = next {
            row.push(next);
            used_tiles.insert(next);
            first = next;
        } else {
            return row;
        }
    }
}

fn compute_image(
    neighbours: &HashMap<u64, Vec<u64>>,
    matching: HashMap<Vec<bool>, Vec<u64>>,
    tiles: &mut HashMap<u64, Tile>,
) -> Vec<Vec<u64>> {
    let mut corner = Vec::new();

    for (&id, connected) in neighbours {
        if connected.len() == 2 && !corner.contains(&id) {
            corner.push(id);
        }
    }

    // Randomly put down the first corner
    let mut used_tiles = HashSet::new();

    let corner_tile = tiles.get_mut(&corner[0]).unwrap();

    // Rotate it until it fits
    while matching[&corner_tile.sides[2]].len() != 2 {
        corner_tile.rotate();
    }

    if matching[&corner_tile.sides[1]].len() != 2 {
        corner_tile.flip();
    }

    debug_assert_eq!(matching[&corner_tile.sides[1]].len(), 2);
    debug_assert_eq!(matching[&corner_tile.sides[2]].len(), 2);

    let rotation = corner_tile.rotations;
    let sides = corner_tile.sides.clone();

    let mut rows = vec![complete_row(corner[0], &neighbours, tiles, &mut used_tiles)];

    debug_assert_eq!(rotation, tiles[&rows[0][0]].rotations);
    debug_assert_eq!(sides, tiles[&rows[0][0]].sides);

    while used_tiles.len() < tiles.len() {
        let prev = rows.last().unwrap()[0];

        // Should be just one tile that can go there.
        let next = neighbours[&prev]
            .iter()
            .filter(|&n| !used_tiles.contains(n))
            .next()
            .unwrap();

        for _ in 0..4 {
            if &tiles[&prev].sides[2] == &tiles[next].sides[0] {
                break;
            } else if rev_eq(&tiles[&prev].sides[2], &tiles[next].sides[0]) {
                tiles.get_mut(next).unwrap().flip();
                break;
            } else {
                tiles.get_mut(next).unwrap().rotate();
            }
        }

        debug_assert_eq!(&tiles[&prev].sides[2], &tiles[next].sides[0]);

        rows.push(complete_row(*next, &neighbours, tiles, &mut used_tiles));
    }

    rows
}

fn combine_tiles(rows: &[Vec<u64>], tiles: &mut HashMap<u64, Tile>) -> Vec<Vec<u8>> {
    // Fix orientation
    for tile in tiles.values_mut() {
        let to_rotate = tile.rotations;

        for _ in 0..to_rotate {
            tile.grid = rotate(&tile.grid);
        }

        if tile.flipped {
            reverse(&mut tile.grid);
        }

        tile.rotations = 0;
        tile.flipped = false;
    }

    rows.iter()
        .flat_map(|row| {
            let len = tiles[row.first().unwrap()].len();

            let mut rows = vec![Vec::new(); len];

            for id in row {
                let tile = &tiles[id];
                for (r, line) in tile.grid.iter().skip(1).take(len).enumerate() {
                    rows[r].extend(
                        line.iter()
                            .skip(1)
                            .take(len)
                            .map(|&b| if b { b'#' } else { b'.' }),
                    );
                }
            }

            rows
        })
        .collect()
}

fn monster_regex() -> [Regex; 3] {
    [
        Regex::new(&"                  # ".replace(' ', ".")).unwrap(),
        Regex::new(&"#    ##    ##    ###".replace(' ', ".")).unwrap(),
        Regex::new(&" #  #  #  #  #  #   ".replace(' ', ".")).unwrap(),
    ]
}

fn rotate<T: Copy>(image: &[Vec<T>]) -> Vec<Vec<T>> {
    let mut new = vec![Vec::new(); image[0].len()];

    for (c, target) in new.iter_mut().enumerate() {
        target.extend(image.iter().rev().map(|r| r[c]));
    }

    new
}

fn reverse<T>(image: &mut [Vec<T>]) {
    for row in image {
        row.reverse();
    }
}

fn replace_monster(image: &mut [Vec<u8>]) {
    let searchers = monster_regex();

    for i in 1..(image.len() - 1) {
        let mut start = 0;

        while let Some(found) = searchers[1].find_at(&image[i], start) {
            start = found.start() + 1;
            let range = found.range();

            if searchers[2].is_match(&image[i + 1][range.clone()])
                && searchers[0].is_match(&image[i - 1][range.clone()])
            {
                image[(i - 1)..=(i + 1)]
                    .iter_mut()
                    .zip(&searchers)
                    .for_each(|(line, expr)| {
                        line[range.clone()]
                            .iter_mut()
                            .zip(expr.as_str().as_bytes().iter())
                            .for_each(|(b, &r)| {
                                if *b == r {
                                    *b = b'O';
                                }
                            })
                    });
            } else if searchers[2].is_match(&image[i - 1][range.clone()])
                && searchers[0].is_match(&image[i + 1][range.clone()])
            {
                image[(i - 1)..=(i + 1)]
                    .iter_mut()
                    .rev()
                    .zip(&searchers)
                    .for_each(|(line, expr)| {
                        line[range.clone()]
                            .iter_mut()
                            .zip(expr.as_str().as_bytes().iter())
                            .for_each(|(b, &r)| {
                                if *b == r {
                                    *b = b'O';
                                }
                            })
                    });
            }
        }
    }
}

#[derive(Default)]
pub struct Day20;

impl Solution for Day20 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let tiles = read_input(input);
        let matching = compute_matching(tiles.values());
        let neighbours = compute_neighbours(matching.values());

        neighbours
            .into_iter()
            .filter_map(|(i, n)| if n.len() == 2 { Some(i) } else { None })
            .fold(1, |a, b| a * b)
            .to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let mut tiles = read_input(input);
        let matching = compute_matching(tiles.values());
        let neighbours = compute_neighbours(matching.values());

        let rows = compute_image(&neighbours, matching, &mut tiles);

        let mut image = combine_tiles(&rows, &mut tiles);

        replace_monster(&mut image);
        reverse(&mut image);
        replace_monster(&mut image);
        image = rotate(&image);
        replace_monster(&mut image);
        reverse(&mut image);
        replace_monster(&mut image);

        image
            .iter()
            .map(|b| bytecount::count(&b, b'#'))
            .sum::<usize>()
            .to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/20.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day20, 1, SAMPLE, 20899048083289u64);
    }

    #[test]
    fn sample_part2() {
        test_implementation!(Day20, 2, SAMPLE, 273);
    }

    #[test]
    fn test_tile_rotate() {
        let mut tile = Tile {
            grid: Vec::new(),
            id: 1,
            sides: [
                vec![false, true],
                vec![false, false, true],
                vec![false, true],
                vec![true, true, false],
            ],
            rotations: 0,
            flipped: false,
        };

        tile.rotate();

        assert_eq!(
            tile.sides,
            [
                vec![false, true, true],
                vec![false, true],
                vec![true, false, false],
                vec![false, true],
            ]
        );
    }

    #[test]
    fn test_tile_flip() {
        let mut tile = Tile {
            grid: Vec::new(),
            id: 1,
            sides: [
                vec![false, true],
                vec![false, false, true],
                vec![false, true],
                vec![true, true, false],
            ],
            rotations: 0,
            flipped: false,
        };

        tile.flip();

        assert_eq!(
            tile.sides,
            [
                vec![true, false],
                vec![true, true, false],
                vec![true, false],
                vec![false, false, true],
            ]
        );
    }

    #[test]
    fn test_rotate() {
        let sample: Vec<Vec<u8>> = vec![
            b"###".as_ref().to_owned(),
            b"  #".as_ref().to_owned(),
            b"# #".as_ref().to_owned(),
        ];

        let rotated = rotate(&sample);

        let correct: Vec<Vec<u8>> = vec![
            b"# #".as_ref().to_owned(),
            b"  #".as_ref().to_owned(),
            b"###".as_ref().to_owned(),
        ];

        assert_eq!(correct, rotated);
    }
}
<commit_msg>Implement clippy warnings.<commit_after>use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;

use regex::bytes::Regex;

use crate::common::Lines;
use crate::Solution;

#[derive(Clone, Debug)]
struct Tile {
    grid: Vec<Vec<bool>>,
    id: u64,
    // NESW order
    sides: [Vec<bool>; 4],
    rotations: u8,
    flipped: bool,
}

impl Tile {
    /// Rotate the slice once to the left. Affects
    fn rotate(&mut self) {
        self.rotations = (self.rotations + 1) % 4;
        self.sides.rotate_right(1);
        self.sides[0].reverse();
        self.sides[2].reverse();
    }

    /// Horizontally flip the tile
    fn flip(&mut self) {
        debug_assert!(!self.flipped);
        self.flipped = !self.flipped;
        self.sides[0].reverse();
        self.sides[2].reverse();
        self.sides.swap(1, 3);
    }

    fn len(&self) -> usize {
        self.grid.len() - 2
    }
}

fn read_input(input: &mut dyn Read) -> HashMap<u64, Tile> {
    let mut tiles = HashMap::new();
    let mut lines = Lines::new(input);

    while let Some(line) = lines.next() {
        let id = line[5..(line.len() - 1)].parse().unwrap();
        drop(line);

        let mut grid: Vec<Vec<_>> = Vec::new();

        // Clippy gets it wrong, this cannot be a for loop
        #[allow(clippy::while_let_on_iterator)]
        while let Some(line) = lines.next() {
            if line.is_empty() {
                break;
            }

            grid.push(line.chars().map(|c| c == '#').collect());
        }

        let sides = [
            grid[0].clone(),
            grid.iter().map(|v| *v.last().unwrap()).collect(),
            grid.last().cloned().unwrap(),
            grid.iter().map(|v| v[0]).collect(),
        ];

        let tile = Tile {
            grid,
            sides,
            id,
            rotations: 0,
            flipped: false,
        };

        tiles.insert(id, tile);
    }

    tiles
}

fn compute_matching<'a>(tiles: impl IntoIterator<Item = &'a Tile>) -> HashMap<Vec<bool>, Vec<u64>> {
    let mut matching: HashMap<Vec<_>, Vec<u64>> = HashMap::new();

    for tile in tiles {
        for side in &tile.sides {
            let neighbours = matching.entry(side.clone()).or_default();

            if !neighbours.contains(&tile.id) {
                neighbours.push(tile.id);
            }

            let mut rev = side.clone();
            rev.reverse();

            let neighbours = matching.entry(rev).or_default();

            if !neighbours.contains(&tile.id) {
                neighbours.push(tile.id);
            }
        }
    }

    // Check if my tile assumption is violated
    debug_assert!(matching.values().map(Vec::len).max().unwrap_or(0) <= 2);

    matching
}

fn compute_neighbours<'a>(
    cliques: impl IntoIterator<Item = &'a Vec<u64>>,
) -> HashMap<u64, Vec<u64>> {
    let mut neighbours: HashMap<u64, Vec<u64>> = HashMap::new();

    for clique in cliques {
        for &a in clique {
            let related = neighbours.entry(a).or_default();

            for &b in clique {
                if a != b && !related.contains(&b) {
                    related.push(b);
                }
            }
        }
    }

    neighbours
}

fn rev_eq(a: &[bool], b: &[bool]) -> bool {
    a.iter().zip(b.iter().rev()).all(|(&a, &b)| a == b)
}

fn complete_row(
    mut first: u64,
    neighbours: &HashMap<u64, Vec<u64>>,
    tiles: &mut HashMap<u64, Tile>,
    used_tiles: &mut HashSet<u64>,
) -> Vec<u64> {
    let mut row = vec![first];
    used_tiles.insert(first);

    loop {
        let last = first;
        let mut next = None;

        for n in &neighbours[&last] {
            if used_tiles.contains(n) {
                continue;
            }

            for _ in 0..4 {
                if tiles[&last].sides[1] == tiles[n].sides[3] {
                    break;
                } else if rev_eq(&tiles[&last].sides[1], &tiles[n].sides[3]) {
                    let tile = tiles.get_mut(n).unwrap();

                    // Vertical flip == horizontal flip + 180
                    tile.rotate();
                    tile.rotate();
                    tile.flip();
                    break;
                } else {
                    tiles.get_mut(&n).unwrap().rotate();
                }
            }

            if tiles[&last].sides[1] == tiles[n].sides[3] {
                // This tile matches, add it
                next = Some(*n);
                break;
            }
        }

        if let Some(next) = next {
            row.push(next);
            used_tiles.insert(next);
            first = next;
        } else {
            return row;
        }
    }
}

fn compute_image(
    neighbours: &HashMap<u64, Vec<u64>>,
    matching: HashMap<Vec<bool>, Vec<u64>>,
    tiles: &mut HashMap<u64, Tile>,
) -> Vec<Vec<u64>> {
    let mut corner = Vec::new();

    for (&id, connected) in neighbours {
        if connected.len() == 2 && !corner.contains(&id) {
            corner.push(id);
        }
    }

    // Randomly put down the first corner
    let mut used_tiles = HashSet::new();

    let corner_tile = tiles.get_mut(&corner[0]).unwrap();

    // Rotate it until it fits
    while matching[&corner_tile.sides[2]].len() != 2 {
        corner_tile.rotate();
    }

    if matching[&corner_tile.sides[1]].len() != 2 {
        corner_tile.flip();
    }

    debug_assert_eq!(matching[&corner_tile.sides[1]].len(), 2);
    debug_assert_eq!(matching[&corner_tile.sides[2]].len(), 2);

    let rotation = corner_tile.rotations;
    let sides = corner_tile.sides.clone();

    let mut rows = vec![complete_row(corner[0], &neighbours, tiles, &mut used_tiles)];

    debug_assert_eq!(rotation, tiles[&rows[0][0]].rotations);
    debug_assert_eq!(sides, tiles[&rows[0][0]].sides);

    while used_tiles.len() < tiles.len() {
        let prev = rows.last().unwrap()[0];

        // Should be just one tile that can go there.
        let next = neighbours[&prev]
            .iter()
            .find(|&n| !used_tiles.contains(n))
            .unwrap();

        for _ in 0..4 {
            if tiles[&prev].sides[2] == tiles[next].sides[0] {
                break;
            } else if rev_eq(&tiles[&prev].sides[2], &tiles[next].sides[0]) {
                tiles.get_mut(next).unwrap().flip();
                break;
            } else {
                tiles.get_mut(next).unwrap().rotate();
            }
        }

        debug_assert_eq!(&tiles[&prev].sides[2], &tiles[next].sides[0]);

        rows.push(complete_row(*next, &neighbours, tiles, &mut used_tiles));
    }

    rows
}

fn combine_tiles(rows: &[Vec<u64>], tiles: &mut HashMap<u64, Tile>) -> Vec<Vec<u8>> {
    // Fix orientation
    for tile in tiles.values_mut() {
        let to_rotate = tile.rotations;

        for _ in 0..to_rotate {
            tile.grid = rotate(&tile.grid);
        }

        if tile.flipped {
            reverse(&mut tile.grid);
        }

        tile.rotations = 0;
        tile.flipped = false;
    }

    rows.iter()
        .flat_map(|row| {
            let len = tiles[row.first().unwrap()].len();

            let mut rows = vec![Vec::new(); len];

            for id in row {
                let tile = &tiles[id];
                for (r, line) in tile.grid.iter().skip(1).take(len).enumerate() {
                    rows[r].extend(
                        line.iter()
                            .skip(1)
                            .take(len)
                            .map(|&b| if b { b'#' } else { b'.' }),
                    );
                }
            }

            rows
        })
        .collect()
}

fn monster_regex() -> [Regex; 3] {
    [
        Regex::new(&"                  # ".replace(' ', ".")).unwrap(),
        Regex::new(&"#    ##    ##    ###".replace(' ', ".")).unwrap(),
        Regex::new(&" #  #  #  #  #  #   ".replace(' ', ".")).unwrap(),
    ]
}

fn rotate<T: Copy>(image: &[Vec<T>]) -> Vec<Vec<T>> {
    let mut new = vec![Vec::new(); image[0].len()];

    for (c, target) in new.iter_mut().enumerate() {
        target.extend(image.iter().rev().map(|r| r[c]));
    }

    new
}

fn reverse<T>(image: &mut [Vec<T>]) {
    for row in image {
        row.reverse();
    }
}

fn replace_monster(image: &mut [Vec<u8>]) {
    let searchers = monster_regex();

    for i in 1..(image.len() - 1) {
        let mut start = 0;

        while let Some(found) = searchers[1].find_at(&image[i], start) {
            start = found.start() + 1;
            let range = found.range();

            if searchers[2].is_match(&image[i + 1][range.clone()])
                && searchers[0].is_match(&image[i - 1][range.clone()])
            {
                image[(i - 1)..=(i + 1)]
                    .iter_mut()
                    .zip(&searchers)
                    .for_each(|(line, expr)| {
                        line[range.clone()]
                            .iter_mut()
                            .zip(expr.as_str().as_bytes().iter())
                            .for_each(|(b, &r)| {
                                if *b == r {
                                    *b = b'O';
                                }
                            })
                    });
            } else if searchers[2].is_match(&image[i - 1][range.clone()])
                && searchers[0].is_match(&image[i + 1][range.clone()])
            {
                image[(i - 1)..=(i + 1)]
                    .iter_mut()
                    .rev()
                    .zip(&searchers)
                    .for_each(|(line, expr)| {
                        line[range.clone()]
                            .iter_mut()
                            .zip(expr.as_str().as_bytes().iter())
                            .for_each(|(b, &r)| {
                                if *b == r {
                                    *b = b'O';
                                }
                            })
                    });
            }
        }
    }
}

#[derive(Default)]
pub struct Day20;

impl Solution for Day20 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let tiles = read_input(input);
        let matching = compute_matching(tiles.values());
        let neighbours = compute_neighbours(matching.values());

        neighbours
            .into_iter()
            .filter_map(|(i, n)| if n.len() == 2 { Some(i) } else { None })
            .product::<u64>()
            .to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let mut tiles = read_input(input);
        let matching = compute_matching(tiles.values());
        let neighbours = compute_neighbours(matching.values());

        let rows = compute_image(&neighbours, matching, &mut tiles);

        let mut image = combine_tiles(&rows, &mut tiles);

        replace_monster(&mut image);
        reverse(&mut image);
        replace_monster(&mut image);
        image = rotate(&image);
        replace_monster(&mut image);
        reverse(&mut image);
        replace_monster(&mut image);

        image
            .iter()
            .map(|b| bytecount::count(&b, b'#'))
            .sum::<usize>()
            .to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/20.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day20, 1, SAMPLE, 20899048083289u64);
    }

    #[test]
    fn sample_part2() {
        test_implementation!(Day20, 2, SAMPLE, 273);
    }

    #[test]
    fn test_tile_rotate() {
        let mut tile = Tile {
            grid: Vec::new(),
            id: 1,
            sides: [
                vec![false, true],
                vec![false, false, true],
                vec![false, true],
                vec![true, true, false],
            ],
            rotations: 0,
            flipped: false,
        };

        tile.rotate();

        assert_eq!(
            tile.sides,
            [
                vec![false, true, true],
                vec![false, true],
                vec![true, false, false],
                vec![false, true],
            ]
        );
    }

    #[test]
    fn test_tile_flip() {
        let mut tile = Tile {
            grid: Vec::new(),
            id: 1,
            sides: [
                vec![false, true],
                vec![false, false, true],
                vec![false, true],
                vec![true, true, false],
            ],
            rotations: 0,
            flipped: false,
        };

        tile.flip();

        assert_eq!(
            tile.sides,
            [
                vec![true, false],
                vec![true, true, false],
                vec![true, false],
                vec![false, false, true],
            ]
        );
    }

    #[test]
    fn test_rotate() {
        let sample: Vec<Vec<u8>> = vec![
            b"###".as_ref().to_owned(),
            b"  #".as_ref().to_owned(),
            b"# #".as_ref().to_owned(),
        ];

        let rotated = rotate(&sample);

        let correct: Vec<Vec<u8>> = vec![
            b"# #".as_ref().to_owned(),
            b"  #".as_ref().to_owned(),
            b"###".as_ref().to_owned(),
        ];

        assert_eq!(correct, rotated);
    }
}
<|endoftext|>


<commit_before>use std::default::Default;

pub struct Chip8 {
    // Clear Display (SDL - black screen)
    pub cls: bool,

    /*
     * 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
     * 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
     * 0x200-0xFFF - Program ROM and work RAM
     */
    pub memory: [u8; 4096],

    /*
     * CPU registers: The Chip 8 has 15 8-bit general purpose registers
     * named V0,V1 up to VE. The 16th register is used  for the ‘carry flag’.
     */
    pub registers: [u8; 16],

    // Index register
    pub i: u16,

    // program counter
    pub pc: u16,

    // Screen - 64 x 32 pixels
    pub graphics: [u8; 64*32],

    // No timers, but 60hz counters
    pub delay_timer: u8,
    pub sound_timer: u8,

    // Stack needed to jump to certain addresses or call subroutines
    // The chip8 stack has 16 levels
    pub stack_pointer: u16,
    pub stack: [u16; 16],

    // Chip8 keypad had 16 keys - keep track of the kb state
    pub keypad: [u8; 16],
}

impl Default for Chip8 {
    #[inline]
    fn default() -> Chip8 {
        Chip8 {
            // Let's clear the screen at start
            cls: true,
            memory: [0u8; 4096],
            registers: [0u8; 16],
            i: 0u16,
            pc: 0x200u16,
            graphics: [0u8; 64*32],
            delay_timer: 0u8,
            sound_timer: 0u8,
            stack_pointer: 0u16,
            stack: [0u16; 16],
            keypad: [0u8; 16],
        }
    }
}

impl Chip8 {
   pub fn cycle(&mut self) {
        // fetch
        let highbits: u8 = self.memory[(self.pc as uint)];
        let lowbits: u8 = self.memory[(self.pc + 1) as uint];
        let mut opcode: u16 = highbits as u16;
        opcode = (opcode << 8) | lowbits as u16;

        // Decode
        match opcode {
            // Clear screen
            0x00e0 => self.cls = true,
            // RET
            0x00ee  => {
                // Move program counter to the top of the stack
                self.pc = self.stack[(self.stack_pointer as uint)];
                // Decrement the stack pointer
                self.stack_pointer -= 1
            },
            // 1nnn - JP addr - jump to nnn
            op @ 0x1000 ... 0x1fff   =>  self.pc = op ^ 0x1000,
            // 2nnn - CALL addr - call subroutine at nnn
            op @ 0x2000 ... 0x2fff   => {
                let nnn = op ^ 0x2000;
                // Increment the stack pointer
                self.stack_pointer += 1;
                // Put the value of pc ontop of the stack
                self.stack[self.stack_pointer as uint] = self.pc;
                // Set the pc to nnn
                self.pc = nnn;
            },
            op @ _ => println!("Unknown opcode: {:X}", op),
        }
        // Execute
        // Increment the counter
        self.pc += 2;
        // Update timers
    }
}
<commit_msg>match SE Vx, byte and SNE Vx, byte<commit_after>use std::default::Default;

pub struct Chip8 {
    // Clear Display (SDL - black screen)
    pub cls: bool,

    /*
     * 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
     * 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
     * 0x200-0xFFF - Program ROM and work RAM
     */
    pub memory: [u8; 4096],

    /*
     * CPU registers: The Chip 8 has 15 8-bit general purpose registers
     * named V0,V1 up to VE. The 16th register is used  for the ‘carry flag’.
     */
    pub registers: [u8; 16],

    // Index register
    pub i: u16,

    // program counter
    pub pc: u16,

    // Screen - 64 x 32 pixels
    pub graphics: [u8; 64*32],

    // No timers, but 60hz counters
    pub delay_timer: u8,
    pub sound_timer: u8,

    // Stack needed to jump to certain addresses or call subroutines
    // The chip8 stack has 16 levels
    pub stack_pointer: u16,
    pub stack: [u16; 16],

    // Chip8 keypad had 16 keys - keep track of the kb state
    pub keypad: [u8; 16],
}

impl Default for Chip8 {
    #[inline]
    fn default() -> Chip8 {
        Chip8 {
            // Let's clear the screen at start
            cls: true,
            memory: [0u8; 4096],
            registers: [0u8; 16],
            i: 0u16,
            pc: 0x200u16,
            graphics: [0u8; 64*32],
            delay_timer: 0u8,
            sound_timer: 0u8,
            stack_pointer: 0u16,
            stack: [0u16; 16],
            keypad: [0u8; 16],
        }
    }
}

impl Chip8 {
   pub fn cycle(&mut self) {
        // fetch
        let highbits: u8 = self.memory[(self.pc as uint)];
        let lowbits: u8 = self.memory[(self.pc + 1) as uint];
        let mut opcode: u16 = highbits as u16;
        opcode = (opcode << 8) | lowbits as u16;

        // Decode
        match opcode {
            // Clear screen
            0x00e0 => self.cls = true,
            // RET
            0x00ee  => {
                // Move program counter to the top of the stack
                self.pc = self.stack[(self.stack_pointer as uint)];
                // Decrement the stack pointer
                self.stack_pointer -= 1
            },
            // 1nnn - JP addr - jump to nnn
            op @ 0x1000 ... 0x1fff   =>  self.pc = op ^ 0x1000,
            // 2nnn - CALL addr - call subroutine at nnn
            op @ 0x2000 ... 0x2fff   => {
                let nnn = op ^ 0x2000;
                // Increment the stack pointer
                self.stack_pointer += 1;
                // Put the value of pc ontop of the stack
                self.stack[self.stack_pointer as uint] = self.pc;
                // Set the pc to nnn
                self.pc = nnn;
            },
            // 3xkk - Skip next instruction if Vx == kk
            op @ 0x3000 ... 0x3fff => {
                let V: u8 = ((op & 0x0F00) >> 8) as u8;
                let byte: u8 = (op & 0x00FF) as u8;
                if self.registers[V as uint] == byte {
                    self.pc += 2;
                }
            },
            // 4xkk - Skip next instruction if Vx != kk
            op @ 0x4000 ... 0x4fff => {
                let V: u8 = ((op & 0x0F00) >> 8) as u8;
                let byte: u8 = (op & 0x00FF) as u8;
                if self.registers[V as uint] != byte {
                    self.pc += 2;
                }
            },
            op @ _ => println!("Unknown opcode: {:X}", op),
        }
        // Execute
        // Increment the counter
        self.pc += 2;
        // Update timers
    }
}
<|endoftext|>


<commit_before><commit_msg>Mark GuestAccessEventContent as non_exhaustive<commit_after><|endoftext|>


<commit_before>/* automatically generated by rust-bindgen */

use bindgen::{glutCreateWindow, glutDestroyWindow, glutDisplayFunc, glutGetWindow, glutInit};
use bindgen::{glutInitDisplayMode, glutPostRedisplay, glutReshapeFunc, glutReshapeWindow};
use bindgen::{glutSetWindow, glutSwapBuffers, glutTimerFunc};
use libc::*;
use dvec::DVec;
use ptr::{addr_of, null};
use str::to_bytes;
use task::local_data::{local_data_get, local_data_set};
use cast::reinterpret_cast;
use vec::raw::to_ptr;

/* FIXME: global variable glutStrokeRoman */

/* FIXME: global variable glutStrokeMonoRoman */

/* FIXME: global variable glutBitmap9By15 */

/* FIXME: global variable glutBitmap8By13 */

/* FIXME: global variable glutBitmapTimesRoman10 */

/* FIXME: global variable glutBitmapTimesRoman24 */

/* FIXME: global variable glutBitmapHelvetica10 */

/* FIXME: global variable glutBitmapHelvetica12 */

/* FIXME: global variable glutBitmapHelvetica18 */

type GLenum = i32;
type GLint = i32;
type GLfloat = f32;
type GLdouble = f64;

enum Window = c_int;

const DOUBLE: c_uint = 2 as c_uint;

fn destroy<T>(-_value: ~[T]) {
    // let it drop
}

fn init() unsafe {
    let argc = 0 as c_int;
    let command = to_bytes(~"glut");
    let argv: (*u8, *u8) = (to_ptr(command), null());
    let argv_p = reinterpret_cast(&addr_of(argv));

    glutInit(addr_of(argc), argv_p);

    destroy(command);
}

fn create_window(name: ~str) -> Window unsafe {
    let bytes = to_bytes(name);
    return Window(glutCreateWindow(to_ptr(bytes) as *c_char));
}

fn destroy_window(window: Window) unsafe {
    glutDestroyWindow(*window);
}

fn reshape_window(window: Window, width: c_int, height: c_int) unsafe {
    let current_window = glutGetWindow();
    glutSetWindow(*window);
    glutReshapeWindow(width, height);
    glutSetWindow(current_window);
}

fn display_callback_tls_key(+_callback: @fn@()) {
    // Empty.
}

extern fn display_callback() unsafe {
    let callback = local_data_get(display_callback_tls_key).get();
    (*callback)();
}

fn display_func(callback: fn@()) unsafe {
    local_data_set(display_callback_tls_key, @callback);
    glutDisplayFunc(display_callback);
}

fn timer_callback_tls_key(+_callback: @DVec<fn@()>) {
    // Empty.
}

extern fn timer_callback(index: int) unsafe {
    let callbacks = local_data_get(timer_callback_tls_key).get();
    ((*callbacks)[index as uint])();
}

fn timer_func(msecs: u32, callback: fn@()) unsafe {
    let callbacks;
    match local_data_get(timer_callback_tls_key) {
        None => {
            callbacks = @DVec();
            local_data_set(timer_callback_tls_key, copy callbacks);
        }
        Some(existing_callbacks) => {
            callbacks = existing_callbacks;
        }
    }

    callbacks.push(callback);
    let index = (callbacks.len() - 1) as c_int;
    glutTimerFunc(msecs, timer_callback, index);
}

fn reshape_callback_tls_key(+_callback: @fn@(++c_int, ++c_int)) {
    // Empty.
}

extern fn reshape_callback(++width: c_int, ++height: c_int) unsafe {
    let callback = local_data_get(reshape_callback_tls_key).get();
    (*callback)(width, height);
}

fn reshape_func(_window: Window, callback: fn@(++c_int, ++c_int)) unsafe {
    local_data_set(reshape_callback_tls_key, @callback);
    glutReshapeFunc(reshape_callback);
}

#[cfg(target_os="macos")]
fn check_loop() unsafe {
    ext::glutCheckLoop();
}

#[cfg(target_os="linux")]
fn check_loop() unsafe {
    ext::glutMainLoopEvent();
}

fn init_display_mode(mode: c_uint) unsafe {
    glutInitDisplayMode(mode);
}

fn swap_buffers() unsafe {
    glutSwapBuffers();
}

fn post_redisplay() unsafe {
    glutPostRedisplay();
}

#[cfg(target_os="macos")]
#[nolink]
#[link_args="-framework GLUT"]
extern mod dummy {
}

#[cfg(target_os="linux")]
#[link_name="glut"]
extern mod dummy {
}

#[cfg(target_os="macos")]
#[nolink]
extern mod ext {
    // Mac GLUT extension.
    fn glutCheckLoop();
}

#[cfg(target_os="linux")]
#[nolink]
extern mod ext {
    // freeglut extension.
    fn glutMainLoopEvent();
}

#[nolink]
extern mod bindgen {

fn glutInit(++argcp: *c_int, ++argv: **c_char);

fn glutInitDisplayMode(++mode: c_uint);

fn glutInitDisplayString(++string: *c_char);

fn glutInitWindowPosition(++x: c_int, ++y: c_int);

fn glutInitWindowSize(++width: c_int, ++height: c_int);

fn glutMainLoop();

fn glutCreateWindow(++title: *c_char) -> c_int;

fn glutCreateSubWindow(++win: c_int, ++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int) -> c_int;

fn glutDestroyWindow(++win: c_int);

fn glutPostRedisplay();

fn glutPostWindowRedisplay(++win: c_int);

fn glutSwapBuffers();

fn glutGetWindow() -> c_int;

fn glutSetWindow(++win: c_int);

fn glutSetWindowTitle(++title: *c_char);

fn glutSetIconTitle(++title: *c_char);

fn glutPositionWindow(++x: c_int, ++y: c_int);

fn glutReshapeWindow(++width: c_int, ++height: c_int);

fn glutPopWindow();

fn glutPushWindow();

fn glutIconifyWindow();

fn glutShowWindow();

fn glutHideWindow();

fn glutFullScreen();

fn glutSetCursor(++cursor: c_int);

fn glutWarpPointer(++x: c_int, ++y: c_int);

fn glutEstablishOverlay();

fn glutRemoveOverlay();

fn glutUseLayer(++layer: GLenum);

fn glutPostOverlayRedisplay();

fn glutPostWindowOverlayRedisplay(++win: c_int);

fn glutShowOverlay();

fn glutHideOverlay();

fn glutCreateMenu(++arg1: *u8) -> c_int;

fn glutDestroyMenu(++menu: c_int);

fn glutGetMenu() -> c_int;

fn glutSetMenu(++menu: c_int);

fn glutAddMenuEntry(++label: *c_char, ++value: c_int);

fn glutAddSubMenu(++label: *c_char, ++submenu: c_int);

fn glutChangeToMenuEntry(++item: c_int, ++label: *c_char, ++value: c_int);

fn glutChangeToSubMenu(++item: c_int, ++label: *c_char, ++submenu: c_int);

fn glutRemoveMenuItem(++item: c_int);

fn glutAttachMenu(++button: c_int);

fn glutDetachMenu(++button: c_int);

fn glutDisplayFunc(++func: *u8);

fn glutReshapeFunc(++func: *u8);

fn glutKeyboardFunc(++func: *u8);

fn glutMouseFunc(++func: *u8);

fn glutMotionFunc(++func: *u8);

fn glutPassiveMotionFunc(++func: *u8);

fn glutEntryFunc(++func: *u8);

fn glutVisibilityFunc(++func: *u8);

fn glutIdleFunc(++func: *u8);

fn glutTimerFunc(++millis: c_uint, ++func: *u8, ++value: c_int);

fn glutMenuStateFunc(++func: *u8);

fn glutSpecialFunc(++func: *u8);

fn glutSpaceballMotionFunc(++func: *u8);

fn glutSpaceballRotateFunc(++func: *u8);

fn glutSpaceballButtonFunc(++func: *u8);

fn glutButtonBoxFunc(++func: *u8);

fn glutDialsFunc(++func: *u8);

fn glutTabletMotionFunc(++func: *u8);

fn glutTabletButtonFunc(++func: *u8);

fn glutMenuStatusFunc(++func: *u8);

fn glutOverlayDisplayFunc(++func: *u8);

fn glutWindowStatusFunc(++func: *u8);

fn glutKeyboardUpFunc(++func: *u8);

fn glutSpecialUpFunc(++func: *u8);

fn glutJoystickFunc(++func: *u8, ++pollInterval: c_int);

fn glutSetColor(++arg1: c_int, ++red: GLfloat, ++green: GLfloat, ++blue: GLfloat);

fn glutGetColor(++ndx: c_int, ++component: c_int) -> GLfloat;

fn glutCopyColormap(++win: c_int);

fn glutGet(++_type: GLenum) -> c_int;

fn glutDeviceGet(++_type: GLenum) -> c_int;

fn glutExtensionSupported(++name: *c_char) -> c_int;

fn glutGetModifiers() -> c_int;

fn glutLayerGet(++_type: GLenum) -> c_int;

fn glutGetProcAddress(++procName: *c_char) -> *c_void;

fn glutBitmapCharacter(++font: *c_void, ++character: c_int);

fn glutBitmapWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutStrokeCharacter(++font: *c_void, ++character: c_int);

fn glutStrokeWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutBitmapLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutStrokeLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutWireSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCube(++size: GLdouble);

fn glutSolidCube(++size: GLdouble);

fn glutWireTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutSolidTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutWireDodecahedron();

fn glutSolidDodecahedron();

fn glutWireTeapot(++size: GLdouble);

fn glutSolidTeapot(++size: GLdouble);

fn glutWireOctahedron();

fn glutSolidOctahedron();

fn glutWireTetrahedron();

fn glutSolidTetrahedron();

fn glutWireIcosahedron();

fn glutSolidIcosahedron();

fn glutVideoResizeGet(++param: GLenum) -> c_int;

fn glutSetupVideoResizing();

fn glutStopVideoResizing();

fn glutVideoResize(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutVideoPan(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutReportErrors();

fn glutIgnoreKeyRepeat(++ignore: c_int);

fn glutSetKeyRepeat(++repeatMode: c_int);

fn glutForceJoystickFunc();

fn glutGameModeString(++string: *c_char);

fn glutEnterGameMode() -> c_int;

fn glutLeaveGameMode();

fn glutGameModeGet(++mode: GLenum) -> c_int;

}
<commit_msg>Update for Rust parser changes<commit_after>/* automatically generated by rust-bindgen */

use bindgen::{glutCreateWindow, glutDestroyWindow, glutDisplayFunc, glutGetWindow, glutInit};
use bindgen::{glutInitDisplayMode, glutPostRedisplay, glutReshapeFunc, glutReshapeWindow};
use bindgen::{glutSetWindow, glutSwapBuffers, glutTimerFunc};
use libc::*;
use dvec::DVec;
use ptr::{addr_of, null};
use str::to_bytes;
use task::local_data::{local_data_get, local_data_set};
use cast::reinterpret_cast;
use vec::raw::to_ptr;

/* FIXME: global variable glutStrokeRoman */

/* FIXME: global variable glutStrokeMonoRoman */

/* FIXME: global variable glutBitmap9By15 */

/* FIXME: global variable glutBitmap8By13 */

/* FIXME: global variable glutBitmapTimesRoman10 */

/* FIXME: global variable glutBitmapTimesRoman24 */

/* FIXME: global variable glutBitmapHelvetica10 */

/* FIXME: global variable glutBitmapHelvetica12 */

/* FIXME: global variable glutBitmapHelvetica18 */

type GLenum = i32;
type GLint = i32;
type GLfloat = f32;
type GLdouble = f64;

enum Window = c_int;

const DOUBLE: c_uint = 2 as c_uint;

fn destroy<T>(-_value: ~[T]) {
    // let it drop
}

fn init() unsafe {
    let argc = 0 as c_int;
    let command = to_bytes(~"glut");
    let argv: (*u8, *u8) = (to_ptr(command), null());
    let argv_p = reinterpret_cast(&addr_of(argv));

    glutInit(addr_of(argc), argv_p);

    destroy(command);
}

fn create_window(name: ~str) -> Window unsafe {
    let bytes = to_bytes(name);
    return Window(glutCreateWindow(to_ptr(bytes) as *c_char));
}

fn destroy_window(window: Window) unsafe {
    glutDestroyWindow(*window);
}

fn reshape_window(window: Window, width: c_int, height: c_int) unsafe {
    let current_window = glutGetWindow();
    glutSetWindow(*window);
    glutReshapeWindow(width, height);
    glutSetWindow(current_window);
}

fn display_callback_tls_key(+_callback: @fn@()) {
    // Empty.
}

extern fn display_callback() unsafe {
    let callback = local_data_get(display_callback_tls_key).get();
    (*callback)();
}

fn display_func(callback: fn@()) unsafe {
    local_data_set(display_callback_tls_key, @callback);
    glutDisplayFunc(display_callback);
}

fn timer_callback_tls_key(+_callback: @DVec<fn@()>) {
    // Empty.
}

extern fn timer_callback(index: int) unsafe {
    let callbacks = local_data_get(timer_callback_tls_key).get();
    ((*callbacks)[index as uint])();
}

fn timer_func(msecs: u32, callback: fn@()) unsafe {
    let callbacks;
    match local_data_get(timer_callback_tls_key) {
        None => {
            callbacks = @DVec();
            local_data_set(timer_callback_tls_key, copy callbacks);
        }
        Some(existing_callbacks) => {
            callbacks = existing_callbacks;
        }
    }

    callbacks.push(callback);
    let index = (callbacks.len() - 1) as c_int;
    glutTimerFunc(msecs, timer_callback, index);
}

fn reshape_callback_tls_key(+_callback: @fn@(x: ++c_int, y: ++c_int)) {
    // Empty.
}

extern fn reshape_callback(++width: c_int, ++height: c_int) unsafe {
    let callback = local_data_get(reshape_callback_tls_key).get();
    (*callback)(width, height);
}

fn reshape_func(_window: Window, callback: fn@(++c_int, ++c_int)) unsafe {
    local_data_set(reshape_callback_tls_key, @callback);
    glutReshapeFunc(reshape_callback);
}

#[cfg(target_os="macos")]
fn check_loop() unsafe {
    ext::glutCheckLoop();
}

#[cfg(target_os="linux")]
fn check_loop() unsafe {
    ext::glutMainLoopEvent();
}

fn init_display_mode(mode: c_uint) unsafe {
    glutInitDisplayMode(mode);
}

fn swap_buffers() unsafe {
    glutSwapBuffers();
}

fn post_redisplay() unsafe {
    glutPostRedisplay();
}

#[cfg(target_os="macos")]
#[nolink]
#[link_args="-framework GLUT"]
extern mod dummy {
}

#[cfg(target_os="linux")]
#[link_name="glut"]
extern mod dummy {
}

#[cfg(target_os="macos")]
#[nolink]
extern mod ext {
    // Mac GLUT extension.
    fn glutCheckLoop();
}

#[cfg(target_os="linux")]
#[nolink]
extern mod ext {
    // freeglut extension.
    fn glutMainLoopEvent();
}

#[nolink]
extern mod bindgen {

fn glutInit(++argcp: *c_int, ++argv: **c_char);

fn glutInitDisplayMode(++mode: c_uint);

fn glutInitDisplayString(++string: *c_char);

fn glutInitWindowPosition(++x: c_int, ++y: c_int);

fn glutInitWindowSize(++width: c_int, ++height: c_int);

fn glutMainLoop();

fn glutCreateWindow(++title: *c_char) -> c_int;

fn glutCreateSubWindow(++win: c_int, ++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int) -> c_int;

fn glutDestroyWindow(++win: c_int);

fn glutPostRedisplay();

fn glutPostWindowRedisplay(++win: c_int);

fn glutSwapBuffers();

fn glutGetWindow() -> c_int;

fn glutSetWindow(++win: c_int);

fn glutSetWindowTitle(++title: *c_char);

fn glutSetIconTitle(++title: *c_char);

fn glutPositionWindow(++x: c_int, ++y: c_int);

fn glutReshapeWindow(++width: c_int, ++height: c_int);

fn glutPopWindow();

fn glutPushWindow();

fn glutIconifyWindow();

fn glutShowWindow();

fn glutHideWindow();

fn glutFullScreen();

fn glutSetCursor(++cursor: c_int);

fn glutWarpPointer(++x: c_int, ++y: c_int);

fn glutEstablishOverlay();

fn glutRemoveOverlay();

fn glutUseLayer(++layer: GLenum);

fn glutPostOverlayRedisplay();

fn glutPostWindowOverlayRedisplay(++win: c_int);

fn glutShowOverlay();

fn glutHideOverlay();

fn glutCreateMenu(++arg1: *u8) -> c_int;

fn glutDestroyMenu(++menu: c_int);

fn glutGetMenu() -> c_int;

fn glutSetMenu(++menu: c_int);

fn glutAddMenuEntry(++label: *c_char, ++value: c_int);

fn glutAddSubMenu(++label: *c_char, ++submenu: c_int);

fn glutChangeToMenuEntry(++item: c_int, ++label: *c_char, ++value: c_int);

fn glutChangeToSubMenu(++item: c_int, ++label: *c_char, ++submenu: c_int);

fn glutRemoveMenuItem(++item: c_int);

fn glutAttachMenu(++button: c_int);

fn glutDetachMenu(++button: c_int);

fn glutDisplayFunc(++func: *u8);

fn glutReshapeFunc(++func: *u8);

fn glutKeyboardFunc(++func: *u8);

fn glutMouseFunc(++func: *u8);

fn glutMotionFunc(++func: *u8);

fn glutPassiveMotionFunc(++func: *u8);

fn glutEntryFunc(++func: *u8);

fn glutVisibilityFunc(++func: *u8);

fn glutIdleFunc(++func: *u8);

fn glutTimerFunc(++millis: c_uint, ++func: *u8, ++value: c_int);

fn glutMenuStateFunc(++func: *u8);

fn glutSpecialFunc(++func: *u8);

fn glutSpaceballMotionFunc(++func: *u8);

fn glutSpaceballRotateFunc(++func: *u8);

fn glutSpaceballButtonFunc(++func: *u8);

fn glutButtonBoxFunc(++func: *u8);

fn glutDialsFunc(++func: *u8);

fn glutTabletMotionFunc(++func: *u8);

fn glutTabletButtonFunc(++func: *u8);

fn glutMenuStatusFunc(++func: *u8);

fn glutOverlayDisplayFunc(++func: *u8);

fn glutWindowStatusFunc(++func: *u8);

fn glutKeyboardUpFunc(++func: *u8);

fn glutSpecialUpFunc(++func: *u8);

fn glutJoystickFunc(++func: *u8, ++pollInterval: c_int);

fn glutSetColor(++arg1: c_int, ++red: GLfloat, ++green: GLfloat, ++blue: GLfloat);

fn glutGetColor(++ndx: c_int, ++component: c_int) -> GLfloat;

fn glutCopyColormap(++win: c_int);

fn glutGet(++_type: GLenum) -> c_int;

fn glutDeviceGet(++_type: GLenum) -> c_int;

fn glutExtensionSupported(++name: *c_char) -> c_int;

fn glutGetModifiers() -> c_int;

fn glutLayerGet(++_type: GLenum) -> c_int;

fn glutGetProcAddress(++procName: *c_char) -> *c_void;

fn glutBitmapCharacter(++font: *c_void, ++character: c_int);

fn glutBitmapWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutStrokeCharacter(++font: *c_void, ++character: c_int);

fn glutStrokeWidth(++font: *c_void, ++character: c_int) -> c_int;

fn glutBitmapLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutStrokeLength(++font: *c_void, ++string: *c_uchar) -> c_int;

fn glutWireSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutSolidCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

fn glutWireCube(++size: GLdouble);

fn glutSolidCube(++size: GLdouble);

fn glutWireTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutSolidTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

fn glutWireDodecahedron();

fn glutSolidDodecahedron();

fn glutWireTeapot(++size: GLdouble);

fn glutSolidTeapot(++size: GLdouble);

fn glutWireOctahedron();

fn glutSolidOctahedron();

fn glutWireTetrahedron();

fn glutSolidTetrahedron();

fn glutWireIcosahedron();

fn glutSolidIcosahedron();

fn glutVideoResizeGet(++param: GLenum) -> c_int;

fn glutSetupVideoResizing();

fn glutStopVideoResizing();

fn glutVideoResize(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutVideoPan(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

fn glutReportErrors();

fn glutIgnoreKeyRepeat(++ignore: c_int);

fn glutSetKeyRepeat(++repeatMode: c_int);

fn glutForceJoystickFunc();

fn glutGameModeString(++string: *c_char);

fn glutEnterGameMode() -> c_int;

fn glutLeaveGameMode();

fn glutGameModeGet(++mode: GLenum) -> c_int;

}
<|endoftext|>