<commit_before>// Copyright 2013-2015, 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 ffi;
use glib::GString;
use glib_ffi;
use std::ptr;
use std::mem;
use glib::translate::*;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Atom(ffi::GdkAtom);

pub const NONE: Atom = Atom(0 as *mut _);
pub const SELECTION_PRIMARY: Atom = Atom(1 as *mut _);
pub const SELECTION_SECONDARY: Atom = Atom(2 as *mut _);
pub const SELECTION_CLIPBOARD: Atom = Atom(69 as *mut _);
pub const TARGET_BITMAP: Atom = Atom(5 as *mut _);
pub const TARGET_COLORMAP: Atom = Atom(7 as *mut _);
pub const TARGET_DRAWABLE: Atom = Atom(17 as *mut _);
pub const TARGET_PIXMAP: Atom = Atom(20 as *mut _);
pub const TARGET_STRING: Atom = Atom(31 as *mut _);
pub const SELECTION_TYPE_ATOM: Atom = Atom(4 as *mut _);
pub const SELECTION_TYPE_BITMAP: Atom = Atom(5 as *mut _);
pub const SELECTION_TYPE_COLORMAP: Atom = Atom(7 as *mut _);
pub const SELECTION_TYPE_DRAWABLE: Atom = Atom(17 as *mut _);
pub const SELECTION_TYPE_INTEGER: Atom = Atom(19 as *mut _);
pub const SELECTION_TYPE_PIXMAP: Atom = Atom(20 as *mut _);
pub const SELECTION_TYPE_WINDOW: Atom = Atom(33 as *mut _);
pub const SELECTION_TYPE_STRING: Atom = Atom(31 as *mut _);

impl Atom {
    pub fn intern(atom_name: &str) -> Atom {
        assert_initialized_main_thread!();
        unsafe { Atom(ffi::gdk_atom_intern(atom_name.to_glib_none().0, false.to_glib())) }
    }

    pub fn name(self) -> GString {
        unsafe { from_glib_full(ffi::gdk_atom_name(self.0)) }
    }

    pub unsafe fn value(self) -> usize {
        self.0 as usize
    }
}

impl GlibPtrDefault for Atom {
    type GlibType = ffi::GdkAtom;
}

#[doc(hidden)]
impl Uninitialized for Atom {
    #[inline]
    unsafe fn uninitialized() -> Self {
        mem::uninitialized()
    }
}

impl<'a> ToGlibPtr<'a, ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, ffi::GdkAtom, Atom> {
        Stash(self.0, ())
    }
}

impl<'a> ToGlibPtrMut<'a, *mut ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GdkAtom, Atom> {
        StashMut(&mut self.0, ())
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GdkAtom> for &'a Atom {
    type Storage = (Vec<Stash<'a, ffi::GdkAtom, &'a Atom>>, Option<Vec<ffi::GdkAtom>>);

    fn to_glib_none_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
        let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
        v_ptr.push(ptr::null_mut());

        (v_ptr.as_ptr() as *mut ffi::GdkAtom, (v, Some(v_ptr)))
    }

    fn to_glib_container_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

        let v_ptr = unsafe {
            let v_ptr = glib_ffi::g_malloc0(mem::size_of::<ffi::GdkAtom>() * (t.len() + 1)) as *mut ffi::GdkAtom;

            for (i, s) in v.iter().enumerate() {
                ptr::write(v_ptr.offset(i as isize), s.0);
            }

            v_ptr
        };

        (v_ptr, (v, None))
    }

    fn to_glib_full_from_slice(_: &[&'a Atom]) -> *mut ffi::GdkAtom {
        skip_assert_initialized!();

        unimplemented!()
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *const ffi::GdkAtom> for &'a Atom {
    type Storage = (Vec<Stash<'a, ffi::GdkAtom, &'a Atom>>, Option<Vec<ffi::GdkAtom>>);

    fn to_glib_none_from_slice(t: &'a [&'a Atom]) -> (*const ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
        let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
        v_ptr.push(ptr::null_mut());

        (v_ptr.as_ptr() as *const ffi::GdkAtom, (v, Some(v_ptr)))
    }

    fn to_glib_container_from_slice(t: &'a [&'a Atom]) -> (*const ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

        let v_ptr = unsafe {
            let v_ptr = glib_ffi::g_malloc0(mem::size_of::<ffi::GdkAtom>() * (t.len() + 1)) as *mut ffi::GdkAtom;

            for (i, s) in v.iter().enumerate() {
                ptr::write(v_ptr.offset(i as isize), s.0);
            }

            v_ptr as *const ffi::GdkAtom
        };

        (v_ptr, (v, None))
    }

    fn to_glib_full_from_slice(_: &[&'a Atom]) -> *const ffi::GdkAtom {
        skip_assert_initialized!();

        unimplemented!()
    }
}

impl FromGlibPtrNone<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_none(ptr: ffi::GdkAtom) -> Atom { Atom(ptr) }
}

impl FromGlibPtrFull<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_full(_: ffi::GdkAtom) -> Atom { unimplemented!() }
}

impl FromGlibContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib_none(ptr::read(ptr.offset(i as isize))));
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib_full(ptr::read(ptr.offset(i as isize))));
        }
        glib_ffi::g_free(ptr as *mut _);
        res
    }
}

impl FromGlibPtrArrayContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
    }
}

impl<'a> From<&'a str> for Atom {
    fn from(r: &'a str) -> Atom {
        skip_assert_initialized!();
        Atom::intern(r)
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*const ffi::GdkAtom> for Atom {
    unsafe fn from_glib_borrow(ptr: *const ffi::GdkAtom) -> Self {
        Atom(*ptr)
    }
}

#[doc(hidden)]
impl FromGlibPtrBorrow<*mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_borrow(ptr: *mut ffi::GdkAtom) -> Self {
        Atom(*ptr)
    }
}
<commit_msg>Replace atom borrow<commit_after>// Copyright 2013-2015, 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 ffi;
use glib::GString;
use glib_ffi;
use std::ptr;
use std::mem;
use glib::translate::*;

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Atom(ffi::GdkAtom);

pub const NONE: Atom = Atom(0 as *mut _);
pub const SELECTION_PRIMARY: Atom = Atom(1 as *mut _);
pub const SELECTION_SECONDARY: Atom = Atom(2 as *mut _);
pub const SELECTION_CLIPBOARD: Atom = Atom(69 as *mut _);
pub const TARGET_BITMAP: Atom = Atom(5 as *mut _);
pub const TARGET_COLORMAP: Atom = Atom(7 as *mut _);
pub const TARGET_DRAWABLE: Atom = Atom(17 as *mut _);
pub const TARGET_PIXMAP: Atom = Atom(20 as *mut _);
pub const TARGET_STRING: Atom = Atom(31 as *mut _);
pub const SELECTION_TYPE_ATOM: Atom = Atom(4 as *mut _);
pub const SELECTION_TYPE_BITMAP: Atom = Atom(5 as *mut _);
pub const SELECTION_TYPE_COLORMAP: Atom = Atom(7 as *mut _);
pub const SELECTION_TYPE_DRAWABLE: Atom = Atom(17 as *mut _);
pub const SELECTION_TYPE_INTEGER: Atom = Atom(19 as *mut _);
pub const SELECTION_TYPE_PIXMAP: Atom = Atom(20 as *mut _);
pub const SELECTION_TYPE_WINDOW: Atom = Atom(33 as *mut _);
pub const SELECTION_TYPE_STRING: Atom = Atom(31 as *mut _);

impl Atom {
    pub fn intern(atom_name: &str) -> Atom {
        assert_initialized_main_thread!();
        unsafe { Atom(ffi::gdk_atom_intern(atom_name.to_glib_none().0, false.to_glib())) }
    }

    pub fn name(self) -> GString {
        unsafe { from_glib_full(ffi::gdk_atom_name(self.0)) }
    }

    pub unsafe fn value(self) -> usize {
        self.0 as usize
    }
}

impl GlibPtrDefault for Atom {
    type GlibType = ffi::GdkAtom;
}

#[doc(hidden)]
impl Uninitialized for Atom {
    #[inline]
    unsafe fn uninitialized() -> Self {
        mem::uninitialized()
    }
}

impl<'a> ToGlibPtr<'a, ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, ffi::GdkAtom, Atom> {
        Stash(self.0, ())
    }
}

impl<'a> ToGlibPtrMut<'a, *mut ffi::GdkAtom> for Atom {
    type Storage = ();

    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GdkAtom, Atom> {
        StashMut(&mut self.0, ())
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GdkAtom> for &'a Atom {
    type Storage = (Vec<Stash<'a, ffi::GdkAtom, &'a Atom>>, Option<Vec<ffi::GdkAtom>>);

    fn to_glib_none_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
        let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
        v_ptr.push(ptr::null_mut());

        (v_ptr.as_ptr() as *mut ffi::GdkAtom, (v, Some(v_ptr)))
    }

    fn to_glib_container_from_slice(t: &'a [&'a Atom]) -> (*mut ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

        let v_ptr = unsafe {
            let v_ptr = glib_ffi::g_malloc0(mem::size_of::<ffi::GdkAtom>() * (t.len() + 1)) as *mut ffi::GdkAtom;

            for (i, s) in v.iter().enumerate() {
                ptr::write(v_ptr.offset(i as isize), s.0);
            }

            v_ptr
        };

        (v_ptr, (v, None))
    }

    fn to_glib_full_from_slice(_: &[&'a Atom]) -> *mut ffi::GdkAtom {
        skip_assert_initialized!();

        unimplemented!()
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *const ffi::GdkAtom> for &'a Atom {
    type Storage = (Vec<Stash<'a, ffi::GdkAtom, &'a Atom>>, Option<Vec<ffi::GdkAtom>>);

    fn to_glib_none_from_slice(t: &'a [&'a Atom]) -> (*const ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();
        let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
        v_ptr.push(ptr::null_mut());

        (v_ptr.as_ptr() as *const ffi::GdkAtom, (v, Some(v_ptr)))
    }

    fn to_glib_container_from_slice(t: &'a [&'a Atom]) -> (*const ffi::GdkAtom, Self::Storage) {
        skip_assert_initialized!();

        let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect();

        let v_ptr = unsafe {
            let v_ptr = glib_ffi::g_malloc0(mem::size_of::<ffi::GdkAtom>() * (t.len() + 1)) as *mut ffi::GdkAtom;

            for (i, s) in v.iter().enumerate() {
                ptr::write(v_ptr.offset(i as isize), s.0);
            }

            v_ptr as *const ffi::GdkAtom
        };

        (v_ptr, (v, None))
    }

    fn to_glib_full_from_slice(_: &[&'a Atom]) -> *const ffi::GdkAtom {
        skip_assert_initialized!();

        unimplemented!()
    }
}

impl FromGlibPtrNone<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_none(ptr: ffi::GdkAtom) -> Atom { Atom(ptr) }
}

impl FromGlibPtrBorrow<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_borrow(ptr: ffi::GdkAtom) -> Atom { Atom(ptr) }
}

impl FromGlibPtrFull<ffi::GdkAtom> for Atom {
    #[inline]
    unsafe fn from_glib_full(_: ffi::GdkAtom) -> Atom { unimplemented!() }
}

impl FromGlibContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib_none(ptr::read(ptr.offset(i as isize))));
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GdkAtom, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib_full(ptr::read(ptr.offset(i as isize))));
        }
        glib_ffi::g_free(ptr as *mut _);
        res
    }
}

impl FromGlibPtrArrayContainerAsVec<ffi::GdkAtom, *mut ffi::GdkAtom> for Atom {
    unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
    }

    unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GdkAtom) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
    }
}

impl<'a> From<&'a str> for Atom {
    fn from(r: &'a str) -> Atom {
        skip_assert_initialized!();
        Atom::intern(r)
    }
}
<|endoftext|>


<commit_before>//! Conditional processing attributes: `requiredExtensions`, `requiredFeatures`, `systemLanguage`.

#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;

use std::str::FromStr;

use language_tags::LanguageTag;
use locale_config::{LanguageRange, Locale};

use crate::error::*;

// No extensions at the moment.
static IMPLEMENTED_EXTENSIONS: &[&str] = &[];

#[derive(Debug, PartialEq)]
pub struct RequiredExtensions(pub bool);

impl RequiredExtensions {
    /// Parse a requiredExtensions attribute.
    ///
    /// http://www.w3.org/TR/SVG/struct.html#RequiredExtensionsAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredExtensions, ValueErrorKind> {
        Ok(RequiredExtensions(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_EXTENSIONS.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredExtensions value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

// Keep these sorted alphabetically for binary_search.
static IMPLEMENTED_FEATURES: &[&str] = &[
    "http://www.w3.org/TR/SVG11/feature#BasicFilter",
    "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicStructure",
    "http://www.w3.org/TR/SVG11/feature#BasicText",
    "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing",
    "http://www.w3.org/TR/SVG11/feature#ContainerAttribute",
    "http://www.w3.org/TR/SVG11/feature#Filter",
    "http://www.w3.org/TR/SVG11/feature#Gradient",
    "http://www.w3.org/TR/SVG11/feature#Image",
    "http://www.w3.org/TR/SVG11/feature#Marker",
    "http://www.w3.org/TR/SVG11/feature#Mask",
    "http://www.w3.org/TR/SVG11/feature#OpacityAttribute",
    "http://www.w3.org/TR/SVG11/feature#Pattern",
    "http://www.w3.org/TR/SVG11/feature#SVG",
    "http://www.w3.org/TR/SVG11/feature#SVG-static",
    "http://www.w3.org/TR/SVG11/feature#Shape",
    "http://www.w3.org/TR/SVG11/feature#Structure",
    "http://www.w3.org/TR/SVG11/feature#Style",
    "http://www.w3.org/TR/SVG11/feature#View",
    "org.w3c.svg.static", // deprecated SVG 1.0 feature string
];

#[derive(Debug, PartialEq)]
pub struct RequiredFeatures(pub bool);

impl RequiredFeatures {
    // Parse a requiredFeatures attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredFeatures, ValueErrorKind> {
        Ok(RequiredFeatures(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_FEATURES.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredFeatures value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

#[derive(Debug, PartialEq)]
pub struct SystemLanguage(pub bool);

impl SystemLanguage {
    /// Parse a `systemLanguage` attribute and match it against a given `Locale`
    ///
    /// The [`systemLanguage`] conditional attribute is a
    /// comma-separated list of [BCP47] Language Tags.  This function
    /// parses the attribute and matches the result against a given
    /// `locale`.  If there is a match, i.e. if the given locale
    /// supports one of the languages listed in the `systemLanguage`
    /// attribute, then the `SystemLanguage.0` will be `true`;
    /// otherwise it will be `false`.
    ///
    /// Normally, calling code will pass `&Locale::current()` for the
    /// `locale` attribute; this is the user's current locale.
    ///
    /// [`systemLanguage`]: https://www.w3.org/TR/SVG/struct.html#ConditionalProcessingSystemLanguageAttribute
    /// [BCP47]: http://www.ietf.org/rfc/bcp/bcp47.txt
    pub fn from_attribute(s: &str, locale: &Locale) -> Result<SystemLanguage, ValueErrorKind> {
        s.split(',')
            .map(str::trim)
            .map(LanguageTag::from_str)
            .try_fold(
                // start with no match
                SystemLanguage(false),
                // The accumulator is Result<SystemLanguage, ValueErrorKind>
                |acc, tag_result| match tag_result {
                    Ok(language_tag) => {
                        let have_match = acc.0;
                        if have_match {
                            Ok(SystemLanguage(have_match))
                        } else {
                            locale_accepts_language_tag(locale, &language_tag).map(SystemLanguage)
                        }
                    }

                    Err(e) => Err(ValueErrorKind::parse_error(&format!(
                        "invalid language tag: \"{}\"",
                        e
                    ))),
                },
            )
    }

    /// Evaluate a systemLanguage value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

fn locale_accepts_language_tag(
    locale: &Locale,
    language_tag: &LanguageTag,
) -> Result<bool, ValueErrorKind> {
    for locale_range in locale.tags_for("messages") {
        if locale_range == LanguageRange::invariant() {
            continue;
        }

        let str_locale_range = locale_range.as_ref();

        let locale_tag = LanguageTag::from_str(str_locale_range).map_err(|e| {
            ValueErrorKind::parse_error(&format!(
                "invalid language tag \"{}\" in locale: {}",
                str_locale_range, e
            ))
        })?;

        if !locale_tag.is_language_range() {
            return Err(ValueErrorKind::value_error(&format!(
                "language tag \"{}\" is not a language range",
                locale_tag
            )));
        }

        if locale_tag.matches(language_tag) {
            return Ok(true);
        }
    }

    Ok(false)
}

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

    #[test]
    fn required_extensions() {
        assert_eq!(
            RequiredExtensions::from_attribute("http://test.org/NotExisting/1.0").unwrap(),
            RequiredExtensions(false)
        );
    }

    #[test]
    fn required_features() {
        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#NotExisting")
                .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#BasicFilter")
                .unwrap(),
            RequiredFeatures(true)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#NotExisting",
            )
            .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#BasicText",
            )
            .unwrap(),
            RequiredFeatures(true)
        );
    }

    #[test]
    fn system_language() {
        let user_prefers = Locale::new("de,en-US").unwrap();

        assert!(SystemLanguage::from_attribute("", &user_prefers).is_err());

        assert!(SystemLanguage::from_attribute("12345", &user_prefers).is_err());

        assert_eq!(
            SystemLanguage::from_attribute("fr", &user_prefers).unwrap(),
            SystemLanguage(false)
        );

        assert_eq!(
            SystemLanguage::from_attribute("en", &user_prefers).unwrap(),
            SystemLanguage(false)
        );

        assert_eq!(
            SystemLanguage::from_attribute("de", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-US", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-GB", &user_prefers).unwrap(),
            SystemLanguage(false)
        );

        assert_eq!(
            SystemLanguage::from_attribute("DE", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("de-LU", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("fr, de", &user_prefers).unwrap(),
            SystemLanguage(true)
        );
    }
}
<commit_msg>Convert the locale to a list of language tags before matching<commit_after>//! Conditional processing attributes: `requiredExtensions`, `requiredFeatures`, `systemLanguage`.

#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;

use std::str::FromStr;

use language_tags::LanguageTag;
use locale_config::{LanguageRange, Locale};

use crate::error::*;

// No extensions at the moment.
static IMPLEMENTED_EXTENSIONS: &[&str] = &[];

#[derive(Debug, PartialEq)]
pub struct RequiredExtensions(pub bool);

impl RequiredExtensions {
    /// Parse a requiredExtensions attribute.
    ///
    /// http://www.w3.org/TR/SVG/struct.html#RequiredExtensionsAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredExtensions, ValueErrorKind> {
        Ok(RequiredExtensions(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_EXTENSIONS.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredExtensions value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

// Keep these sorted alphabetically for binary_search.
static IMPLEMENTED_FEATURES: &[&str] = &[
    "http://www.w3.org/TR/SVG11/feature#BasicFilter",
    "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicStructure",
    "http://www.w3.org/TR/SVG11/feature#BasicText",
    "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing",
    "http://www.w3.org/TR/SVG11/feature#ContainerAttribute",
    "http://www.w3.org/TR/SVG11/feature#Filter",
    "http://www.w3.org/TR/SVG11/feature#Gradient",
    "http://www.w3.org/TR/SVG11/feature#Image",
    "http://www.w3.org/TR/SVG11/feature#Marker",
    "http://www.w3.org/TR/SVG11/feature#Mask",
    "http://www.w3.org/TR/SVG11/feature#OpacityAttribute",
    "http://www.w3.org/TR/SVG11/feature#Pattern",
    "http://www.w3.org/TR/SVG11/feature#SVG",
    "http://www.w3.org/TR/SVG11/feature#SVG-static",
    "http://www.w3.org/TR/SVG11/feature#Shape",
    "http://www.w3.org/TR/SVG11/feature#Structure",
    "http://www.w3.org/TR/SVG11/feature#Style",
    "http://www.w3.org/TR/SVG11/feature#View",
    "org.w3c.svg.static", // deprecated SVG 1.0 feature string
];

#[derive(Debug, PartialEq)]
pub struct RequiredFeatures(pub bool);

impl RequiredFeatures {
    // Parse a requiredFeatures attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredFeatures, ValueErrorKind> {
        Ok(RequiredFeatures(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_FEATURES.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredFeatures value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

/// A list of BCP47 language tags.
///
/// https://www.rfc-editor.org/info/rfc5664
pub struct LanguageTags(Vec<LanguageTag>);

impl LanguageTags {
    /// Converts a `Locale` to a set of language tags.
    pub fn from_locale(locale: &Locale) -> Result<LanguageTags, String> {
        let mut tags = Vec::new();

        for locale_range in locale.tags_for("messages") {
            if locale_range == LanguageRange::invariant() {
                continue;
            }

            let str_locale_range = locale_range.as_ref();

            let locale_tag = LanguageTag::from_str(str_locale_range).map_err(|e| {
                format!(
                    "invalid language tag \"{}\" in locale: {}",
                    str_locale_range, e
                )
            })?;

            if !locale_tag.is_language_range() {
                return Err(format!(
                    "language tag \"{}\" is not a language range",
                    locale_tag
                ));
            }

            tags.push(locale_tag);
        }

        Ok(LanguageTags(tags))
    }

    fn any_matches(&self, language_tag: &LanguageTag) -> bool {
        self.0.iter().any(|tag| tag.matches(language_tag))
    }
}

#[derive(Debug, PartialEq)]
pub struct SystemLanguage(pub bool);

impl SystemLanguage {
    /// Parse a `systemLanguage` attribute and match it against a given `Locale`
    ///
    /// The [`systemLanguage`] conditional attribute is a
    /// comma-separated list of [BCP47] Language Tags.  This function
    /// parses the attribute and matches the result against a given
    /// `locale`.  If there is a match, i.e. if the given locale
    /// supports one of the languages listed in the `systemLanguage`
    /// attribute, then the `SystemLanguage.0` will be `true`;
    /// otherwise it will be `false`.
    ///
    /// Normally, calling code will pass `&Locale::current()` for the
    /// `locale` attribute; this is the user's current locale.
    ///
    /// [`systemLanguage`]: https://www.w3.org/TR/SVG/struct.html#ConditionalProcessingSystemLanguageAttribute
    /// [BCP47]: http://www.ietf.org/rfc/bcp/bcp47.txt
    pub fn from_attribute(s: &str, locale: &Locale) -> Result<SystemLanguage, ValueErrorKind> {
        s.split(',')
            .map(str::trim)
            .map(LanguageTag::from_str)
            .try_fold(
                // start with no match
                SystemLanguage(false),
                // The accumulator is Result<SystemLanguage, ValueErrorKind>
                |acc, tag_result| match tag_result {
                    Ok(language_tag) => {
                        let have_match = acc.0;
                        if have_match {
                            Ok(SystemLanguage(have_match))
                        } else {
                            locale_accepts_language_tag(locale, &language_tag).map(SystemLanguage)
                        }
                    }

                    Err(e) => Err(ValueErrorKind::parse_error(&format!(
                        "invalid language tag: \"{}\"",
                        e
                    ))),
                },
            )
    }

    /// Evaluate a systemLanguage value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

fn locale_accepts_language_tag(
    locale: &Locale,
    language_tag: &LanguageTag,
) -> Result<bool, ValueErrorKind> {
    let tags = LanguageTags::from_locale(locale).map_err(|e| ValueErrorKind::value_error(&e))?;

    Ok(tags.any_matches(language_tag))
}

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

    #[test]
    fn required_extensions() {
        assert_eq!(
            RequiredExtensions::from_attribute("http://test.org/NotExisting/1.0").unwrap(),
            RequiredExtensions(false)
        );
    }

    #[test]
    fn required_features() {
        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#NotExisting")
                .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#BasicFilter")
                .unwrap(),
            RequiredFeatures(true)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#NotExisting",
            )
            .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#BasicText",
            )
            .unwrap(),
            RequiredFeatures(true)
        );
    }

    #[test]
    fn system_language() {
        let user_prefers = Locale::new("de,en-US").unwrap();

        assert!(SystemLanguage::from_attribute("", &user_prefers).is_err());

        assert!(SystemLanguage::from_attribute("12345", &user_prefers).is_err());

        assert_eq!(
            SystemLanguage::from_attribute("fr", &user_prefers).unwrap(),
            SystemLanguage(false)
        );

        assert_eq!(
            SystemLanguage::from_attribute("en", &user_prefers).unwrap(),
            SystemLanguage(false)
        );

        assert_eq!(
            SystemLanguage::from_attribute("de", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-US", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-GB", &user_prefers).unwrap(),
            SystemLanguage(false)
        );

        assert_eq!(
            SystemLanguage::from_attribute("DE", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("de-LU", &user_prefers).unwrap(),
            SystemLanguage(true)
        );

        assert_eq!(
            SystemLanguage::from_attribute("fr, de", &user_prefers).unwrap(),
            SystemLanguage(true)
        );
    }
}
<|endoftext|>


<commit_before>use memory::Fetch;
use executor::execute;
use decoder::decode_16;
use decoder::decode_32;
use decoder::is_thumb32;
use register::Reg;

pub enum ProcessorMode {
    ThreadMode,
    HandlerMode,
}

pub struct Core<'a, T: Fetch + 'a> {
    pub msp: u32,
    pub psp: u32,
    pub r: [u32; 16],

    pub apsr: u32,
    pub ipsr: u32,
    pub epsr: u32,

    pub primask: u32,
    pub control: u32,

    pub mode: ProcessorMode,
    pub memory: &'a mut T,
}

impl<'a, T: Fetch> Core<'a, T> {
    pub fn new(memory: &'a mut T) -> Core<'a, T> {
        Core {
            mode: ProcessorMode::ThreadMode,
            msp: 0,
            psp: 0,
            apsr: 0,
            ipsr: 0,
            epsr: 0,
            primask: 0,
            control: 0,
            r: [0; 16],
            memory: memory,
        }
    }

    pub fn reset(&mut self) {
        let reset_vector = self.memory.fetch32(4);

        self.r[Reg::PC.value()] = reset_vector & 0xfffffffe;
        self.epsr = (reset_vector & 1) << 24;
        self.msp = self.memory.fetch32(0);
    }

    //
    // fetch, decode and execute single instruction
    //
    pub fn run(&mut self) {
        let hw = self.memory.fetch16(self.r[Reg::PC.value()]);

        let op = match is_thumb32(hw) {
            true => {
                let hw2 = self.memory.fetch16(self.r[Reg::PC.value()] + 2);
                println!("pc 0x{:X} = 0x{:X}, 0x{:X}", self.r[Reg::PC.value()], hw, hw2);
                decode_32(hw, hw2)
            }
            false => {
                println!("pc 0x{:X} = 0x{:X}", self.r[Reg::PC.value()], hw);
                decode_16(hw)
            }
        };

        execute(self, op);
    }
}
<commit_msg>print registers for debugging<commit_after>use memory::Fetch;
use executor::execute;
use decoder::decode_16;
use decoder::decode_32;
use decoder::is_thumb32;
use register::Reg;

pub enum ProcessorMode {
    ThreadMode,
    HandlerMode,
}

pub struct Core<'a, T: Fetch + 'a> {
    pub msp: u32,
    pub psp: u32,
    pub r: [u32; 16],

    pub apsr: u32,
    pub ipsr: u32,
    pub epsr: u32,

    pub primask: u32,
    pub control: u32,

    pub mode: ProcessorMode,
    pub memory: &'a mut T,
}

impl<'a, T: Fetch> Core<'a, T> {
    pub fn new(memory: &'a mut T) -> Core<'a, T> {
        Core {
            mode: ProcessorMode::ThreadMode,
            msp: 0,
            psp: 0,
            apsr: 0,
            ipsr: 0,
            epsr: 0,
            primask: 0,
            control: 0,
            r: [0; 16],
            memory: memory,
        }
    }

    pub fn reset(&mut self) {
        let reset_vector = self.memory.fetch32(4);
        println!("\nRESET");

        self.r[Reg::PC.value()] = reset_vector & 0xfffffffe;
        self.epsr = (reset_vector & 1) << 24;
        self.msp = self.memory.fetch32(0);
    }

    //
    // fetch, decode and execute single instruction
    //
    pub fn run(&mut self) {
        let hw = self.memory.fetch16(self.r[Reg::PC.value()]);

        let op = match is_thumb32(hw) {
            true => {
                let hw2 = self.memory.fetch16(self.r[Reg::PC.value()] + 2);
                //println!("pc 0x{:X} = 0x{:X}, 0x{:X}",
                //         self.r[Reg::PC.value()],
                //         hw,
                //         hw2);
                decode_32(hw, hw2)
            }
            false => {
                //println!("pc 0x{:X} = 0x{:X}", self.r[Reg::PC.value()], hw);
                decode_16(hw)
            }
        };

        execute(self, op);
        //TODO: print only changed registers
        //TODO: print APSR
        //TODO: print memory accesses
        println!("PC:{:08X} LR:{:08X} R0:{:08X} R1:{:08X} R2:{:08X} R3:{:08X} R4:{:08X} R5:{:08X} \
                  R6:{:08X} R7:{:08X} R8:{:08X}",
                 self.r[Reg::PC.value()],
                 self.r[Reg::LR.value()],
                 self.r[Reg::R0.value()],
                 self.r[Reg::R1.value()],
                 self.r[Reg::R2.value()],
                 self.r[Reg::R3.value()],
                 self.r[Reg::R4.value()],
                 self.r[Reg::R5.value()],
                 self.r[Reg::R6.value()],
                 self.r[Reg::R7.value()],
                 self.r[Reg::R8.value()]);
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json;
use std::collections::HashMap;
use std::io::File;
use std::os;

pub fn load() -> HashMap<String, String> {
    let data = match File::open(&data_file_path()).read_to_string() {
        Ok(contents) => contents,
        Err(_) => "{}".to_string()
    };

    json::decode(data.as_slice()).unwrap()
}

pub fn save(rump_data: HashMap<String, String>) {
    let data = json::encode(&rump_data);

    File::create(&data_file_path()).write_str(data.as_slice()).ok();
}

fn data_file_path() -> Path {
    let home = os::homedir().unwrap();
    let mut path = Path::new(home);
    path.push(".rump");
    path
}
<commit_msg>std::io --> std::old_io<commit_after>use rustc_serialize::json;
use std::collections::HashMap;
use std::old_io::File;
use std::os;

pub fn load() -> HashMap<String, String> {
    let data = match File::open(&data_file_path()).read_to_string() {
        Ok(contents) => contents,
        Err(_) => "{}".to_string()
    };

    json::decode(data.as_slice()).unwrap()
}

pub fn save(rump_data: HashMap<String, String>) {
    let data = json::encode(&rump_data);

    File::create(&data_file_path()).write_str(data.as_slice()).ok();
}

fn data_file_path() -> Path {
    let home = os::homedir().unwrap();
    let mut path = Path::new(home);
    path.push(".rump");
    path
}
<|endoftext|>


<commit_before>use ffi::types::{hid_t, hsize_t, hbool_t};
use ffi::h5i::H5I_INVALID_HID;
use ffi::h5p::{H5P_FILE_CREATE, H5P_FILE_ACCESS, H5Pcreate, H5Pset_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fclose, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist};
use ffi::drivers::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use object::{Handle, Object};
use error::Result;
use plist::PropertyList;
use ffi::util::string_to_cstr;
use std::path::{Path, PathBuf};

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl File {
    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode == H5F_ACC_RDONLY
        }
    }

    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new(filename).mode(mode).open()
    }

    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }
}

impl Drop for File {
    fn drop(&mut self) {
        if self.refcount() == 1 {
            h5lock!(H5Fclose(self.id()));
        }
    }
}

pub struct FileBuilder {
    filename: PathBuf,
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new<P: AsRef<Path>>(filename: P) -> FileBuilder {
        FileBuilder {
            filename: filename.as_ref().to_path_buf(),
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
        match self.driver.as_ref() {
            "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
            "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
            "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                               self.filebacked as hbool_t)),
            _       => fail!(format!("Invalid file driver: {}", self.driver)),
        };
        Ok(fapl)
    }

    fn open_file(&self, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            match self.filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", self.filename)
            }
        })
    }

    fn create_file(&self, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            match self.filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", self.filename)
            }
        })
    }

    pub fn open(&self) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(false),
            "r+"       => self.open_file(true),
            "w"        => self.create_file(false),
            "w-" | "x" => self.create_file(true),
            "a"        => match self.open_file(true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::File;
    use std::path::PathBuf;
    use tempdir::TempDir;

    fn with_tmpdir<F: Fn(PathBuf)>(f: F) {
        let dir = TempDir::new_in(".", "tmp").unwrap();
        let path = dir.path().to_path_buf();
        f(path);
    }

    #[test]
    pub fn test_invalid_mode() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        with_tmpdir(|dir| {
            let path = dir.join("foo.h5");
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_invalid_filename() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });
    }
}
<commit_msg>Use h5lock!() for File::make_fapl()<commit_after>use ffi::types::{hid_t, hsize_t, hbool_t};
use ffi::h5i::H5I_INVALID_HID;
use ffi::h5p::{H5P_FILE_CREATE, H5P_FILE_ACCESS, H5Pcreate, H5Pset_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fclose, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist};
use ffi::drivers::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use object::{Handle, Object};
use error::Result;
use plist::PropertyList;
use ffi::util::string_to_cstr;
use std::path::{Path, PathBuf};

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl File {
    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode == H5F_ACC_RDONLY
        }
    }

    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new(filename).mode(mode).open()
    }

    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }
}

impl Drop for File {
    fn drop(&mut self) {
        if self.refcount() == 1 {
            h5lock!(H5Fclose(self.id()));
        }
    }
}

pub struct FileBuilder {
    filename: PathBuf,
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new<P: AsRef<Path>>(filename: P) -> FileBuilder {
        FileBuilder {
            filename: filename.as_ref().to_path_buf(),
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        h5lock_s!({
            let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
            match self.driver.as_ref() {
                "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
                "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
                "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                                   self.filebacked as hbool_t)),
                _       => fail!(format!("Invalid file driver: {}", self.driver)),
            };
            Ok(fapl)
        })
    }

    fn open_file(&self, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            match self.filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", self.filename)
            }
        })
    }

    fn create_file(&self, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            match self.filename.to_str() {
                Some(filename) => {
                    let c_filename = string_to_cstr(filename);
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", self.filename)
            }
        })
    }

    pub fn open(&self) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(false),
            "r+"       => self.open_file(true),
            "w"        => self.create_file(false),
            "w-" | "x" => self.create_file(true),
            "a"        => match self.open_file(true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::File;
    use std::path::PathBuf;
    use tempdir::TempDir;

    fn with_tmpdir<F: Fn(PathBuf)>(f: F) {
        let dir = TempDir::new_in(".", "tmp").unwrap();
        let path = dir.path().to_path_buf();
        f(path);
    }

    #[test]
    pub fn test_invalid_mode() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        with_tmpdir(|dir| {
            let path = dir.join("foo.h5");
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "a").unwrap().is_read_only());
        });
        with_tmpdir(|dir| {
            assert!(!File::open(dir.join("foo.h"), "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_invalid_filename() {
        with_tmpdir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });
    }
}
<|endoftext|>


<commit_before>// To search for nibbles in a byte array.
// Requires two nibbles per byte.
// All values above 0x0F will be used as wildcard.
// Example: Use x or X as wildcard for a nibble.

pub trait FindOptSubset {
    fn find_subset(&self, subset: &[u8]) -> Option<usize>;
}

impl FindOptSubset for Vec<u8> {
    fn find_subset(&self, subset: &[u8]) -> Option<usize> {
        if subset.len() > 2 * self.len() {
            return None;
        }
        if subset.len() % 2 != 0 {
            // Must be dividable by two
            return None;
        }
        // Search in a for b
        for a in 0..self.len() - subset.len() / 2 + 1 {
            for b in 0..subset.len() / 2 {
                // if b is not a, skip searching at that position in a
                // Logic: both match, ...
                // or first nibble matches when second nibble is wildcard,
                // or second nibble matches when first nibble is wildcard.
                // or two wildcards at that position.
                if !(
                    ((subset[2*b  ] == self[a + b]>>4) && (subset[2*b+1] == self[a + b]%16)) ||
                    ((subset[2*b  ] == self[a + b]>>4) && (subset[2*b+1] >= 0x10)) ||
                    ((subset[2*b+1] == self[a + b]%16) && (subset[2*b  ] >= 0x10)) ||
                    ((subset[2*b+1] >= 0x10) && (subset[2*b  ] >= 0x10))
                   ) {
                    break; // element does not match
                }
                // when all elements of b match in a, return position of a
                if b == subset.len() / 2 - 1 {
                    return Some(a);
                }
            }
        }
        None
    }
}

#[test]
fn find_subset_partial_at_start() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x01];
    assert_eq!(buf.find_subset(&sub), Some(0));
}
#[test]
fn find_subset_partial_at_middle() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x03, 0x00, 0x04];
    assert_eq!(buf.find_subset(&sub), Some(2));
}
#[test]
fn find_subset_partial_at_end() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x04, 0x00, 0x05];
    assert_eq!(buf.find_subset(&sub), Some(3));
}
#[test]
fn find_subset_partial_after_end() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x05, 0x00, 0x06];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_partial_before_start() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x00, 0x00, 0x01];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_short() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x02];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_subset_too_long() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![
        0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06,
    ];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_full() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05];
    assert_eq!(buf.find_subset(&sub), Some(0));
}
#[test]
fn find_subset_swapped() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_higher_than_9() {
    let buf = vec![0x0A, 0x0C, 0x0D, 0x0E, 0x0F];
    let sub = vec![0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_subset_higher_than_f() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 0x01, 0x0D, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_single_wildcard_0x10() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 0x01, 0x10, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_wildcard_0xf0() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 0xF0, 0xF0, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_wildcard_xX() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 'x' as u8, 'X' as u8, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_wildcards() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x10, 0x10, 0x10, 0x10, 0x10, 0x10];
    assert_eq!(buf.find_subset(&sub), Some(0));
}
#[test]
fn find_shifted() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x0A, 0x03];
    assert_eq!(buf.find_subset(&sub), None);
}
<commit_msg>Save condition from rustfmt<commit_after>// To search for nibbles in a byte array.
// Requires two nibbles per byte.
// All values above 0x0F will be used as wildcard.
// Example: Use x or X as wildcard for a nibble.

pub trait FindOptSubset {
    fn find_subset(&self, subset: &[u8]) -> Option<usize>;
}

impl FindOptSubset for Vec<u8> {
    fn find_subset(&self, subset: &[u8]) -> Option<usize> {
        if subset.len() > 2 * self.len() {
            return None;
        }
        if subset.len() % 2 != 0 {
            // Must be dividable by two
            return None;
        }
        // Search in a for b
        for a in 0..self.len() - subset.len() / 2 + 1 {
            for b in 0..subset.len() / 2 {
                // if b is not a, skip searching at that position in a
                // Logic: both match, ...
                // or first nibble matches when second nibble is wildcard,
                // or second nibble matches when first nibble is wildcard.
                // or two wildcards at that position.
                #![rustfmt::skip]
                if !(
                    ((subset[2*b  ] == self[a + b]>>4) && (subset[2*b+1] == self[a + b]%16)) ||
                    ((subset[2*b  ] == self[a + b]>>4) && (subset[2*b+1] >= 0x10)) ||
                    ((subset[2*b+1] == self[a + b]%16) && (subset[2*b  ] >= 0x10)) ||
                    ((subset[2*b+1] >= 0x10) && (subset[2*b  ] >= 0x10))
                   )
                {
                    break; // element does not match
                }
                // when all elements of b match in a, return position of a
                if b == subset.len() / 2 - 1 {
                    return Some(a);
                }
            }
        }
        None
    }
}

#[test]
fn find_subset_partial_at_start() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x01];
    assert_eq!(buf.find_subset(&sub), Some(0));
}
#[test]
fn find_subset_partial_at_middle() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x03, 0x00, 0x04];
    assert_eq!(buf.find_subset(&sub), Some(2));
}
#[test]
fn find_subset_partial_at_end() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x04, 0x00, 0x05];
    assert_eq!(buf.find_subset(&sub), Some(3));
}
#[test]
fn find_subset_partial_after_end() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x05, 0x00, 0x06];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_partial_before_start() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x00, 0x00, 0x01];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_short() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x02];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_subset_too_long() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![
        0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06,
    ];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_full() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05];
    assert_eq!(buf.find_subset(&sub), Some(0));
}
#[test]
fn find_subset_swapped() {
    let buf = vec![0x01, 0x02, 0x03, 0x04, 0x05];
    let sub = vec![0x00, 0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01];
    assert_eq!(buf.find_subset(&sub), None);
}
#[test]
fn find_subset_higher_than_9() {
    let buf = vec![0x0A, 0x0C, 0x0D, 0x0E, 0x0F];
    let sub = vec![0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_subset_higher_than_f() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 0x01, 0x0D, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_single_wildcard_0x10() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 0x01, 0x10, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_wildcard_0xf0() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 0xF0, 0xF0, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_wildcard_xX() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x03, 0x0C, 'x' as u8, 'X' as u8, 0x0E, 0x0E];
    assert_eq!(buf.find_subset(&sub), Some(1));
}
#[test]
fn find_with_wildcards() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x10, 0x10, 0x10, 0x10, 0x10, 0x10];
    assert_eq!(buf.find_subset(&sub), Some(0));
}
#[test]
fn find_shifted() {
    let buf = vec![0x0A, 0x3C, 0x1D, 0xEE, 0x0F];
    let sub = vec![0x0A, 0x03];
    assert_eq!(buf.find_subset(&sub), None);
}
<|endoftext|>


<commit_before>use ::actions;
use ::board;

use std::hash::{Hash, Hasher, SipHasher};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Role {
    Dwarf,
    Troll,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Player {
    role: Role,
    name: String,
}

impl Player {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn role(&self) -> Role {
        self.role
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum EndProposal {
    Neither,
    Single(PlayerMarker),
    Both,
}

impl EndProposal {
    fn advance(&mut self, player: PlayerMarker) {
        *self = match *self {
            EndProposal::Single(p) if p != player => EndProposal::Both,
            EndProposal::Neither => EndProposal::Single(player),
            _ => *self,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PlayerMarker {
    One,
    Two,
}

impl PlayerMarker {
    fn index(self) -> usize {
        match self {
            PlayerMarker::One => 0,
            PlayerMarker::Two => 1,
        }
    }

    fn toggle(&mut self) {
        *self = match *self {
            PlayerMarker::One => PlayerMarker::Two,
            PlayerMarker::Two => PlayerMarker::One,
        }
    }
}

pub struct State {
    board: board::Cells,
    players: [Player; 2],
    active_player: PlayerMarker,
    end_proposal: EndProposal,
}

impl State {
    pub fn new(board: board::Cells, player1_name: String, player2_name: String) -> Self {
        State {
            board: board,
            players: [Player { role: Role::Dwarf, name: player1_name, },
                      Player { role: Role::Troll, name: player2_name, },],
            active_player: PlayerMarker::One,
            end_proposal: EndProposal::Neither,
        }
    }

    pub fn new_default(player1_name: String, player2_name: String) -> Self {
        State::new(board::Cells::default(), player1_name, player2_name)
    }

    pub fn active_player(&self) -> &Player {
        &self.players[self.active_player.index()]
    }

    pub fn role_actions<'s>(&'s self, r: Role) -> actions::ActionIterator<'s> {
        self.board.role_actions(r)
    }

    pub fn position_actions<'s>(&'s self, position: board::Coordinate) -> actions::ActionIterator<'s> {
        self.board.position_actions(position)
    }

    pub fn toggle_active_player(&mut self) {
        self.active_player.toggle()
    }

    pub fn do_action(&mut self, a: &actions::Action) {
        match a {
            &actions::Action::Concede => self.end_proposal.advance(self.active_player),
            _ => self.board.do_action(a),
        }
        self.active_player.toggle();
    }

    pub fn terminated(&self) -> bool {
        self.end_proposal == EndProposal::Both
    }

    pub fn board(&self) -> &board::Cells {
        &self.board
    }

    pub fn player(&self, p: PlayerMarker) -> &Player {
        &self.players[p.index()]
    }

    pub fn end_proposal(&self) -> EndProposal {
        self.end_proposal
    }
}

impl Clone for State {
    fn clone(&self) -> Self {
        State {
            board: self.board.clone(),
            players: [self.players[0].clone(),
                      self.players[1].clone()],
            active_player: self.active_player,
            end_proposal: self.end_proposal,
        }
    }
}

pub struct Transpositions {
    state: State,
}

impl Transpositions {
    pub fn new(state: State) -> Self {
        Transpositions { state: state, }
    }
}

impl PartialEq<State> for Transpositions {
    fn eq(&self, other: &State) -> bool {
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                for &c in [board::Coordinate::new_unchecked(row, col),
                           board::Coordinate::new_unchecked(7u8 - row, col),
                           board::Coordinate::new_unchecked(row, 7u8 - col),
                           board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                           board::Coordinate::new_unchecked(col, row),
                           board::Coordinate::new_unchecked(7u8 - col, row),
                           board::Coordinate::new_unchecked(col, 7u8 - row),
                           board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)].iter() {
                    if self.state.board[c] != other.board[c] {
                        return false
                    }
                }
            }
        }
        true
    }
}

impl PartialEq<Transpositions> for Transpositions {
    fn eq(&self, other: &Transpositions) -> bool {
        self.eq(&other.state)
    }
}

impl Eq for Transpositions { }

impl Hash for Transpositions {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let mut hashers = [SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new()];
        for h in &mut hashers {
            self.state.end_proposal.hash(h);
        }
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                let mut i = 0;
                for &c in &[board::Coordinate::new_unchecked(row, col),
                            board::Coordinate::new_unchecked(7u8 - row, col),
                            board::Coordinate::new_unchecked(row, 7u8 - col),
                            board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                            board::Coordinate::new_unchecked(col, row),
                            board::Coordinate::new_unchecked(7u8 - col, row),
                            board::Coordinate::new_unchecked(col, 7u8 - row),
                            board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)] {
                    self.state.board[c].hash(&mut hashers[i]);
                    i += 1;
                }
            }
        }
        let mut hash_values = [hashers[0].finish(),
                               hashers[1].finish(),
                               hashers[2].finish(),
                               hashers[3].finish(),
                               hashers[4].finish(),
                               hashers[5].finish(),
                               hashers[6].finish(),
                               hashers[7].finish()];
        (&mut hash_values).sort();
        for v in &hash_values {
            state.write_u64(*v);
        }
    }
}
<commit_msg>Make game::State support transpositions directly.<commit_after>use ::actions;
use ::board;

use std::hash::{Hash, Hasher, SipHasher};

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Role {
    Dwarf,
    Troll,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Player {
    role: Role,
    name: String,
}

impl Player {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn role(&self) -> Role {
        self.role
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum EndProposal {
    Neither,
    Single(PlayerMarker),
    Both,
}

impl EndProposal {
    fn advance(&mut self, player: PlayerMarker) {
        *self = match *self {
            EndProposal::Single(p) if p != player => EndProposal::Both,
            EndProposal::Neither => EndProposal::Single(player),
            _ => *self,
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PlayerMarker {
    One,
    Two,
}

impl PlayerMarker {
    fn index(self) -> usize {
        match self {
            PlayerMarker::One => 0,
            PlayerMarker::Two => 1,
        }
    }

    fn toggle(&mut self) {
        *self = match *self {
            PlayerMarker::One => PlayerMarker::Two,
            PlayerMarker::Two => PlayerMarker::One,
        }
    }
}

pub struct State {
    board: board::Cells,
    players: [Player; 2],
    active_player: PlayerMarker,
    end_proposal: EndProposal,
}

impl State {
    pub fn new(board: board::Cells, player1_name: String, player2_name: String) -> Self {
        State {
            board: board,
            players: [Player { role: Role::Dwarf, name: player1_name, },
                      Player { role: Role::Troll, name: player2_name, },],
            active_player: PlayerMarker::One,
            end_proposal: EndProposal::Neither,
        }
    }

    pub fn new_default(player1_name: String, player2_name: String) -> Self {
        State::new(board::Cells::default(), player1_name, player2_name)
    }

    pub fn active_player(&self) -> &Player {
        &self.players[self.active_player.index()]
    }

    pub fn role_actions<'s>(&'s self, r: Role) -> actions::ActionIterator<'s> {
        self.board.role_actions(r)
    }

    pub fn position_actions<'s>(&'s self, position: board::Coordinate) -> actions::ActionIterator<'s> {
        self.board.position_actions(position)
    }

    pub fn toggle_active_player(&mut self) {
        self.active_player.toggle()
    }

    pub fn do_action(&mut self, a: &actions::Action) {
        match a {
            &actions::Action::Concede => self.end_proposal.advance(self.active_player),
            _ => self.board.do_action(a),
        }
        self.active_player.toggle();
    }

    pub fn terminated(&self) -> bool {
        self.end_proposal == EndProposal::Both
    }

    pub fn board(&self) -> &board::Cells {
        &self.board
    }

    pub fn player(&self, p: PlayerMarker) -> &Player {
        &self.players[p.index()]
    }

    pub fn end_proposal(&self) -> EndProposal {
        self.end_proposal
    }
}

impl Clone for State {
    fn clone(&self) -> Self {
        State {
            board: self.board.clone(),
            players: [self.players[0].clone(),
                      self.players[1].clone()],
            active_player: self.active_player,
            end_proposal: self.end_proposal,
        }
    }
}

impl PartialEq<State> for State {
    fn eq(&self, other: &State) -> bool {
        if self.active_player != other.active_player
            || self.end_proposal == other.end_proposal
            || self.players[0].role() == other.players[0].role() {
                return false
            }
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                for &c in [board::Coordinate::new_unchecked(row, col),
                           board::Coordinate::new_unchecked(7u8 - row, col),
                           board::Coordinate::new_unchecked(row, 7u8 - col),
                           board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                           board::Coordinate::new_unchecked(col, row),
                           board::Coordinate::new_unchecked(7u8 - col, row),
                           board::Coordinate::new_unchecked(col, 7u8 - row),
                           board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)].iter() {
                    if self.board[c] != other.board[c] {
                        return false
                    }
                }
            }
        }
        true
    }
}

impl Eq for State { }

impl Hash for State {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let mut hashers = [SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new(),
                           SipHasher::new()];
        for h in &mut hashers {
            self.active_player.hash(h);
            self.players[0].role().hash(h);
            self.players[1].role().hash(h);
            self.end_proposal.hash(h);
        }
        for row in 0u8..8u8 {
            for col in 0u8..8u8 {
                let mut i = 0;
                for &c in &[board::Coordinate::new_unchecked(row, col),
                            board::Coordinate::new_unchecked(7u8 - row, col),
                            board::Coordinate::new_unchecked(row, 7u8 - col),
                            board::Coordinate::new_unchecked(7u8 - row, 7u8 - col),
                            board::Coordinate::new_unchecked(col, row),
                            board::Coordinate::new_unchecked(7u8 - col, row),
                            board::Coordinate::new_unchecked(col, 7u8 - row),
                            board::Coordinate::new_unchecked(7u8 - col, 7u8 - row)] {
                    self.board[c].hash(&mut hashers[i]);
                    i += 1;
                }
            }
        }
        let mut hash_values = [hashers[0].finish(),
                               hashers[1].finish(),
                               hashers[2].finish(),
                               hashers[3].finish(),
                               hashers[4].finish(),
                               hashers[5].finish(),
                               hashers[6].finish(),
                               hashers[7].finish()];
        (&mut hash_values).sort();
        for v in &hash_values {
            state.write_u64(*v);
        }
    }
}
<|endoftext|>


<commit_before>use std::mem::{size_of_val, transmute};
use std::ptr::null_mut;

use libc::funcs::c95::stdlib::{free, malloc};
use libc::{c_void, size_t};

use util::{MIN_MATCH, WINDOW_MASK};

pub struct Hash {
    /// Hash value to index of its most recent occurrence.
    pub head: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev: *mut u16,
    /// Index to hash value at this index.
    pub hashval: *mut i32,
    /// Current hash value.
    pub val: i32,

    pub hash_same_hash: HashSameHash,
    pub hash_same: HashSame,
}

#[cfg(not(feature = "hash-same-hash"))]
pub struct HashSameHash;

#[cfg(feature = "hash-same-hash")]
/// Fields with similar purpose as the above hash, but for the second hash with
/// a value that is calculated differently.
pub struct HashSameHash {
    /// Hash value to index of its most recent occurrence.
    pub head2: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev2: *mut u16,
    /// Index to hash value at this index.
    pub hashval2: *mut i32,
    /// Current hash value.
    pub val2: i32,
}

impl HashSameHash {
    #[cfg(not(feature = "hash-same-hash"))]
    fn new(window_size: usize) -> HashSameHash {
        HashSameHash
    }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn new(window_size: usize) -> HashSameHash {
        let mut head2: *mut i32 = null_mut();
        head2 = transmute(malloc(size_of_val(&*head2) as size_t * 65536));
        let mut prev2: *mut u16 = null_mut();
        prev2 = transmute(malloc((size_of_val(&*prev2) * window_size) as size_t));
        let mut hashval2: *mut i32 = null_mut();
        hashval2 = transmute(malloc((size_of_val(&*hashval2) * window_size) as size_t));
        for i in 0..65536 {
            *head2.offset(i) = -1;
        }
        for i in 0..window_size {
            *prev2.offset(i as isize) = i as u16;
            *hashval2.offset(i as isize) = -1;
        }

        HashSameHash {
            head2: head2,
            prev2: prev2,
            hashval2: hashval2,
            val2: 0,
        }
    }

    #[cfg(not(feature = "hash-same-hash"))]
    fn clean(h: *const HashSameHash) { }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn clean(h: *const HashSameHash) {
        free((*h).head2 as *mut c_void);
        free((*h).prev2 as *mut c_void);
        free((*h).hashval2 as *mut c_void);
    }
}

#[cfg(not(feature = "hash-same"))]
pub struct HashSame;

#[cfg(feature = "hash-same")]
pub struct HashSame {
    /// Amount of repetitions of same byte after this.
    pub same: *mut u16,
}

impl HashSame {
    #[cfg(not(feature = "hash-same"))]
    fn new(window_size: usize) -> HashSame {
        HashSame
    }

    #[cfg(feature = "hash-same")]
    unsafe fn new(window_size: usize) -> HashSame {
        let mut same: *mut u16 = null_mut();
        same = transmute(malloc((size_of_val(&*same) * window_size) as size_t));
        for i in 0..window_size {
            *same.offset(i as isize) = 0;
        }
        HashSame {
            same: same
        }
    }

    #[cfg(not(feature = "hash-same"))]
    fn clean(h: *const HashSame) { }

    #[cfg(feature = "hash-same")]
    unsafe fn clean(h: *const HashSame) {
        free((*h).same as *mut c_void);
    }
}

const HASH_SHIFT: u32 = 5;
const HASH_MASK: i32 = 32767;

impl Hash {
    pub unsafe fn new(window_size: usize) -> Hash {
        let mut head: *mut i32 = null_mut();
        head = transmute(malloc(size_of_val(&*head) as size_t * 65536));
        let mut prev: *mut u16 = null_mut();
        prev = transmute(malloc((size_of_val(&*prev) * window_size) as size_t));
        let mut hashval: *mut i32 = null_mut();
        hashval = transmute(malloc((size_of_val(&*hashval) * window_size) as size_t));

        for i in 0..65536 {
            // -1 indicates no head so far.
            *head.offset(i) = -1;
        }
        for i in 0..window_size {
            // If prev[j] == j, then prev[j] is uninitialized.
            *prev.offset(i as isize) = i as u16;
            *hashval.offset(i as isize) = -1;
        }

        Hash {
            head: head,
            prev: prev,
            hashval: hashval,
            val: 0,
            hash_same: HashSame::new(window_size),
            hash_same_hash: HashSameHash::new(window_size),
        }
    }

    pub unsafe fn clean(h: *mut Hash) {
        free((*h).head as *mut c_void);
        free((*h).prev as *mut c_void);
        free((*h).hashval as *mut c_void);

        HashSameHash::clean(&(*h).hash_same_hash as *const _);
        HashSame::clean(&(*h).hash_same as *const _);
    }
}

/// Update the sliding hash value with the given byte. All calls to this function
/// must be made on consecutive input characters. Since the hash value exists out
/// of multiple input bytes, a few warmups with this function are needed initially.
unsafe fn update_hash_value(h: *mut Hash, c: u8) {
    (*h).val = (((*h).val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
}

#[cfg(not(feature = "hash-same"))]
fn update_hash_same(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) { }

#[cfg(feature = "hash-same")]
unsafe fn update_hash_same(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) {
    let mut amount: usize = 0;
    if *(*h).hash_same.same.offset(((pos - 1) & WINDOW_MASK) as isize) > 1 {
        amount = (*(*h).hash_same.same.offset(((pos - 1) & WINDOW_MASK) as isize) - 1) as usize;
    }
    while pos + amount + 1 < end && *array.offset(pos as isize) == *array.offset((pos + amount + 1) as isize) && amount < (-1 as u16) as usize {
        amount += 1;
    }
    *(*h).hash_same.same.offset(hpos as isize) = amount as u16;
}

#[cfg(not(feature = "hash-same-hash"))]
fn update_hash_same_hash(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) { }

#[cfg(feature = "hash-same-hash")]
unsafe fn update_hash_same_hash(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) {
    (*h).hash_same_hash.val2 = (((*(*h).hash_same.same.offset(hpos as isize) - MIN_MATCH as u16) & 255) ^ (*h).val as u16) as i32;
    *(*h).hash_same_hash.hashval2.offset(hpos as isize) = (*h).hash_same_hash.val2;
    if *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) != -1 && *(*h).hash_same_hash.hashval2.offset(*(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as isize) == (*h).hash_same_hash.val2 {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as u16;
    } else {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = hpos;
    }
    *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) = hpos as i32;
}

pub unsafe fn update_hash(array: *const u8, pos: usize, end: usize, h: *mut Hash) {
    let hpos: u16 = pos as u16 & WINDOW_MASK as u16;
    update_hash_value(h, if pos + MIN_MATCH <= end { *array.offset(pos as isize + MIN_MATCH as isize - 1) } else { 0 });
    *(*h).hashval.offset(hpos as isize) = (*h).val;
    if *(*h).head.offset((*h).val as isize) != -1 && *(*h).hashval.offset(*(*h).head.offset((*h).val as isize) as isize) == (*h).val {
        *(*h).prev.offset(hpos as isize) = *(*h).head.offset((*h).val as isize) as u16;
    } else {
        *(*h).prev.offset(hpos as isize) = hpos;
    }
    *(*h).head.offset((*h).val as isize) = hpos as i32;

    update_hash_same(array, pos, end, hpos, h);
    update_hash_same_hash(array, pos, end, hpos, h);
}

pub unsafe fn warmup_hash(array: *const u8, pos: usize, end: usize, h: *mut Hash) {
    update_hash_value(h, *array.offset(pos as isize + 0));
    update_hash_value(h, *array.offset(pos as isize + 1));
}
<commit_msg>Fix compile error on nightly rust<commit_after>use std::mem::{size_of_val, transmute};
use std::ptr::null_mut;

use libc::funcs::c95::stdlib::{free, malloc};
use libc::{c_void, size_t};

use util::{MIN_MATCH, WINDOW_MASK};

pub struct Hash {
    /// Hash value to index of its most recent occurrence.
    pub head: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev: *mut u16,
    /// Index to hash value at this index.
    pub hashval: *mut i32,
    /// Current hash value.
    pub val: i32,

    pub hash_same_hash: HashSameHash,
    pub hash_same: HashSame,
}

#[cfg(not(feature = "hash-same-hash"))]
pub struct HashSameHash;

#[cfg(feature = "hash-same-hash")]
/// Fields with similar purpose as the above hash, but for the second hash with
/// a value that is calculated differently.
pub struct HashSameHash {
    /// Hash value to index of its most recent occurrence.
    pub head2: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev2: *mut u16,
    /// Index to hash value at this index.
    pub hashval2: *mut i32,
    /// Current hash value.
    pub val2: i32,
}

impl HashSameHash {
    #[cfg(not(feature = "hash-same-hash"))]
    fn new(window_size: usize) -> HashSameHash {
        HashSameHash
    }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn new(window_size: usize) -> HashSameHash {
        let mut head2: *mut i32 = null_mut();
        head2 = transmute(malloc(size_of_val(&*head2) as size_t * 65536));
        let mut prev2: *mut u16 = null_mut();
        prev2 = transmute(malloc((size_of_val(&*prev2) * window_size) as size_t));
        let mut hashval2: *mut i32 = null_mut();
        hashval2 = transmute(malloc((size_of_val(&*hashval2) * window_size) as size_t));
        for i in 0..65536 {
            *head2.offset(i) = -1;
        }
        for i in 0..window_size {
            *prev2.offset(i as isize) = i as u16;
            *hashval2.offset(i as isize) = -1;
        }

        HashSameHash {
            head2: head2,
            prev2: prev2,
            hashval2: hashval2,
            val2: 0,
        }
    }

    #[cfg(not(feature = "hash-same-hash"))]
    fn clean(h: *const HashSameHash) { }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn clean(h: *const HashSameHash) {
        free((*h).head2 as *mut c_void);
        free((*h).prev2 as *mut c_void);
        free((*h).hashval2 as *mut c_void);
    }
}

#[cfg(not(feature = "hash-same"))]
pub struct HashSame;

#[cfg(feature = "hash-same")]
pub struct HashSame {
    /// Amount of repetitions of same byte after this.
    pub same: *mut u16,
}

impl HashSame {
    #[cfg(not(feature = "hash-same"))]
    fn new(window_size: usize) -> HashSame {
        HashSame
    }

    #[cfg(feature = "hash-same")]
    unsafe fn new(window_size: usize) -> HashSame {
        let mut same: *mut u16 = null_mut();
        same = transmute(malloc((size_of_val(&*same) * window_size) as size_t));
        for i in 0..window_size {
            *same.offset(i as isize) = 0;
        }
        HashSame {
            same: same
        }
    }

    #[cfg(not(feature = "hash-same"))]
    fn clean(h: *const HashSame) { }

    #[cfg(feature = "hash-same")]
    unsafe fn clean(h: *const HashSame) {
        free((*h).same as *mut c_void);
    }
}

const HASH_SHIFT: u32 = 5;
const HASH_MASK: i32 = 32767;

impl Hash {
    pub unsafe fn new(window_size: usize) -> Hash {
        let mut head: *mut i32 = null_mut();
        head = transmute(malloc(size_of_val(&*head) as size_t * 65536));
        let mut prev: *mut u16 = null_mut();
        prev = transmute(malloc((size_of_val(&*prev) * window_size) as size_t));
        let mut hashval: *mut i32 = null_mut();
        hashval = transmute(malloc((size_of_val(&*hashval) * window_size) as size_t));

        for i in 0..65536 {
            // -1 indicates no head so far.
            *head.offset(i) = -1;
        }
        for i in 0..window_size {
            // If prev[j] == j, then prev[j] is uninitialized.
            *prev.offset(i as isize) = i as u16;
            *hashval.offset(i as isize) = -1;
        }

        Hash {
            head: head,
            prev: prev,
            hashval: hashval,
            val: 0,
            hash_same: HashSame::new(window_size),
            hash_same_hash: HashSameHash::new(window_size),
        }
    }

    pub unsafe fn clean(h: *mut Hash) {
        free((*h).head as *mut c_void);
        free((*h).prev as *mut c_void);
        free((*h).hashval as *mut c_void);

        HashSameHash::clean(&(*h).hash_same_hash as *const _);
        HashSame::clean(&(*h).hash_same as *const _);
    }
}

/// Update the sliding hash value with the given byte. All calls to this function
/// must be made on consecutive input characters. Since the hash value exists out
/// of multiple input bytes, a few warmups with this function are needed initially.
unsafe fn update_hash_value(h: *mut Hash, c: u8) {
    (*h).val = (((*h).val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
}

#[cfg(not(feature = "hash-same"))]
fn update_hash_same(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) { }

#[cfg(feature = "hash-same")]
unsafe fn update_hash_same(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) {
    let mut amount: usize = 0;
    if *(*h).hash_same.same.offset(((pos - 1) & WINDOW_MASK) as isize) > 1 {
        amount = (*(*h).hash_same.same.offset(((pos - 1) & WINDOW_MASK) as isize) - 1) as usize;
    }
    while pos + amount + 1 < end && *array.offset(pos as isize) == *array.offset((pos + amount + 1) as isize) && amount < !0u16 as usize {
        amount += 1;
    }
    *(*h).hash_same.same.offset(hpos as isize) = amount as u16;
}

#[cfg(not(feature = "hash-same-hash"))]
fn update_hash_same_hash(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) { }

#[cfg(feature = "hash-same-hash")]
unsafe fn update_hash_same_hash(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) {
    (*h).hash_same_hash.val2 = (((*(*h).hash_same.same.offset(hpos as isize) - MIN_MATCH as u16) & 255) ^ (*h).val as u16) as i32;
    *(*h).hash_same_hash.hashval2.offset(hpos as isize) = (*h).hash_same_hash.val2;
    if *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) != -1 && *(*h).hash_same_hash.hashval2.offset(*(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as isize) == (*h).hash_same_hash.val2 {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as u16;
    } else {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = hpos;
    }
    *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) = hpos as i32;
}

pub unsafe fn update_hash(array: *const u8, pos: usize, end: usize, h: *mut Hash) {
    let hpos: u16 = pos as u16 & WINDOW_MASK as u16;
    update_hash_value(h, if pos + MIN_MATCH <= end { *array.offset(pos as isize + MIN_MATCH as isize - 1) } else { 0 });
    *(*h).hashval.offset(hpos as isize) = (*h).val;
    if *(*h).head.offset((*h).val as isize) != -1 && *(*h).hashval.offset(*(*h).head.offset((*h).val as isize) as isize) == (*h).val {
        *(*h).prev.offset(hpos as isize) = *(*h).head.offset((*h).val as isize) as u16;
    } else {
        *(*h).prev.offset(hpos as isize) = hpos;
    }
    *(*h).head.offset((*h).val as isize) = hpos as i32;

    update_hash_same(array, pos, end, hpos, h);
    update_hash_same_hash(array, pos, end, hpos, h);
}

pub unsafe fn warmup_hash(array: *const u8, pos: usize, end: usize, h: *mut Hash) {
    update_hash_value(h, *array.offset(pos as isize + 0));
    update_hash_value(h, *array.offset(pos as isize + 1));
}
<|endoftext|>