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

//! Unwind library interface

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)] // these are just bindings

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
pub use self::_Unwind_Action::*;
#[cfg(target_arch = "arm")]
pub use self::_Unwind_State::*;
pub use self::_Unwind_Reason_Code::*;

use libc;

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
#[repr(C)]
#[derive(Copy, Clone)]
pub enum _Unwind_Action {
    _UA_SEARCH_PHASE = 1,
    _UA_CLEANUP_PHASE = 2,
    _UA_HANDLER_FRAME = 4,
    _UA_FORCE_UNWIND = 8,
    _UA_END_OF_STACK = 16,
}

#[cfg(target_arch = "arm")]
#[repr(C)]
#[derive(Copy, Clone)]
pub enum _Unwind_State {
    _US_VIRTUAL_UNWIND_FRAME = 0,
    _US_UNWIND_FRAME_STARTING = 1,
    _US_UNWIND_FRAME_RESUME = 2,
    _US_ACTION_MASK = 3,
    _US_FORCE_UNWIND = 8,
    _US_END_OF_STACK = 16
}

#[repr(C)]
#[derive(Copy, Clone)]
pub enum _Unwind_Reason_Code {
    _URC_NO_REASON = 0,
    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
    _URC_FATAL_PHASE2_ERROR = 2,
    _URC_FATAL_PHASE1_ERROR = 3,
    _URC_NORMAL_STOP = 4,
    _URC_END_OF_STACK = 5,
    _URC_HANDLER_FOUND = 6,
    _URC_INSTALL_CONTEXT = 7,
    _URC_CONTINUE_UNWIND = 8,
    _URC_FAILURE = 9, // used only by ARM EABI
}

pub type _Unwind_Exception_Class = u64;

pub type _Unwind_Word = libc::uintptr_t;

#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: usize = 6;

#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
pub const unwinder_private_data_size: usize = 20;

#[cfg(all(target_arch = "arm", target_os = "ios"))]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "aarch64")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "powerpc")]
pub const unwinder_private_data_size: usize = 2;

#[repr(C)]
pub struct _Unwind_Exception {
    pub exception_class: _Unwind_Exception_Class,
    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
    pub private: [_Unwind_Word; unwinder_private_data_size],
}

pub enum _Unwind_Context {}

pub type _Unwind_Exception_Cleanup_Fn =
        extern "C" fn(unwind_code: _Unwind_Reason_Code,
                      exception: *mut _Unwind_Exception);

#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
               target_os = "freebsd"),
           link(name = "gcc_s"))]
#[cfg_attr(all(target_os = "linux", target_env = "musl", not(test)),
           link(name = "unwind", kind = "static"))]
#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
           link(name = "gcc"))]
#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
           link(name = "gcc"))]
#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
           link(name = "unwind"))]
#[cfg_attr(target_os = "dragonfly",
           link(name = "gcc_pic"))]
#[cfg_attr(target_os = "bitrig",
           link(name = "c++abi"))]
#[cfg_attr(all(target_os = "windows", target_env="gnu"),
           link(name = "gcc_eh"))]
extern "C" {
    // iOS on armv7 uses SjLj exceptions and requires to link
    // against corresponding routine (..._SjLj_...)
    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
    #[unwind]
    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
                                  -> _Unwind_Reason_Code;

    #[cfg(all(target_os = "ios", target_arch = "arm"))]
    #[unwind]
    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
                                   -> _Unwind_Reason_Code;

    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);

    #[unwind]
    pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
}

// ... and now we just providing access to SjLj counterspart
// through a standard name to hide those details from others
// (see also comment above regarding _Unwind_RaiseException)
#[cfg(all(target_os = "ios", target_arch = "arm"))]
#[inline(always)]
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
                                     -> _Unwind_Reason_Code {
    _Unwind_SjLj_RaiseException(exc)
}
<commit_msg>Fix stage0 ICE caused by the old _Unwind_Resume override trickery.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Unwind library interface

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)] // these are just bindings

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
pub use self::_Unwind_Action::*;
#[cfg(target_arch = "arm")]
pub use self::_Unwind_State::*;
pub use self::_Unwind_Reason_Code::*;

use libc;

#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
#[repr(C)]
#[derive(Copy, Clone)]
pub enum _Unwind_Action {
    _UA_SEARCH_PHASE = 1,
    _UA_CLEANUP_PHASE = 2,
    _UA_HANDLER_FRAME = 4,
    _UA_FORCE_UNWIND = 8,
    _UA_END_OF_STACK = 16,
}

#[cfg(target_arch = "arm")]
#[repr(C)]
#[derive(Copy, Clone)]
pub enum _Unwind_State {
    _US_VIRTUAL_UNWIND_FRAME = 0,
    _US_UNWIND_FRAME_STARTING = 1,
    _US_UNWIND_FRAME_RESUME = 2,
    _US_ACTION_MASK = 3,
    _US_FORCE_UNWIND = 8,
    _US_END_OF_STACK = 16
}

#[repr(C)]
#[derive(Copy, Clone)]
pub enum _Unwind_Reason_Code {
    _URC_NO_REASON = 0,
    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
    _URC_FATAL_PHASE2_ERROR = 2,
    _URC_FATAL_PHASE1_ERROR = 3,
    _URC_NORMAL_STOP = 4,
    _URC_END_OF_STACK = 5,
    _URC_HANDLER_FOUND = 6,
    _URC_INSTALL_CONTEXT = 7,
    _URC_CONTINUE_UNWIND = 8,
    _URC_FAILURE = 9, // used only by ARM EABI
}

pub type _Unwind_Exception_Class = u64;

pub type _Unwind_Word = libc::uintptr_t;

#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: usize = 6;

#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
pub const unwinder_private_data_size: usize = 20;

#[cfg(all(target_arch = "arm", target_os = "ios"))]
pub const unwinder_private_data_size: usize = 5;

#[cfg(target_arch = "aarch64")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "powerpc")]
pub const unwinder_private_data_size: usize = 2;

#[repr(C)]
pub struct _Unwind_Exception {
    pub exception_class: _Unwind_Exception_Class,
    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
    pub private: [_Unwind_Word; unwinder_private_data_size],
}

pub enum _Unwind_Context {}

pub type _Unwind_Exception_Cleanup_Fn =
        extern "C" fn(unwind_code: _Unwind_Reason_Code,
                      exception: *mut _Unwind_Exception);

#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
               target_os = "freebsd"),
           link(name = "gcc_s"))]
#[cfg_attr(all(target_os = "linux", target_env = "musl", not(test)),
           link(name = "unwind", kind = "static"))]
#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
           link(name = "gcc"))]
#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
           link(name = "gcc"))]
#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
           link(name = "unwind"))]
#[cfg_attr(target_os = "dragonfly",
           link(name = "gcc_pic"))]
#[cfg_attr(target_os = "bitrig",
           link(name = "c++abi"))]
#[cfg_attr(all(target_os = "windows", target_env="gnu"),
           link(name = "gcc_eh"))]
extern "C" {
    // iOS on armv7 uses SjLj exceptions and requires to link
    // against corresponding routine (..._SjLj_...)
    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
    #[unwind]
    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
                                  -> _Unwind_Reason_Code;

    #[cfg(all(target_os = "ios", target_arch = "arm"))]
    #[unwind]
    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
                                   -> _Unwind_Reason_Code;

    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);

    // remove cfg after new snapshot
    #[cfg(not(all(stage0, target_os="windows", target_arch="x86_64")))]
    #[unwind]
    pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
}

// ... and now we just providing access to SjLj counterspart
// through a standard name to hide those details from others
// (see also comment above regarding _Unwind_RaiseException)
#[cfg(all(target_os = "ios", target_arch = "arm"))]
#[inline(always)]
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
                                     -> _Unwind_Reason_Code {
    _Unwind_SjLj_RaiseException(exc)
}
<|endoftext|>


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

#![unstable(feature = "collections_range",
            reason = "waiting for dust to settle on inclusive ranges",
            issue = "30877")]

//! Range syntax.

use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
use Bound::{self, Excluded, Included, Unbounded};

/// **RangeArgument** is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T: ?Sized> {
    /// Start index bound
    ///
    /// Return start value as a `Bound`
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(collections)]
    /// #![feature(collections_range)]
    /// #![feature(collections_bound)]
    ///
    /// extern crate collections;
    ///
    /// # fn main() {
    /// use collections::range::RangeArgument;
    /// use collections::Bound::*;
    ///
    /// assert_eq!((..10).start(), Unbounded);
    /// assert_eq!((3..10).start(), Included(&3));
    /// # }
    /// ```
    fn start(&self) -> Bound<&T> {
        Unbounded
    }

    /// End index bound
    ///
    /// Return end value as a `Bound`
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(collections)]
    /// #![feature(collections_range)]
    /// #![feature(collections_bound)]
    ///
    /// extern crate collections;
    ///
    /// # fn main() {
    /// use collections::range::RangeArgument;
    /// use collections::Bound::*;
    ///
    /// assert_eq!((3..).end(), Unbounded);
    /// assert_eq!((3..10).end(), Excluded(&10));
    /// # }
    /// ```
    fn end(&self) -> Bound<&T> {
        Unbounded
    }
}

// FIXME add inclusive ranges to RangeArgument

impl<T: ?Sized> RangeArgument<T> for RangeFull {}

impl<T> RangeArgument<T> for RangeFrom<T> {
    fn start(&self) -> Bound<&T> {
        Included(&self.start)
    }
}

impl<T> RangeArgument<T> for RangeTo<T> {
    fn end(&self) -> Bound<&T> {
        Excluded(&self.end)
    }
}

impl<T> RangeArgument<T> for Range<T> {
    fn start(&self) -> Bound<&T> {
        Included(&self.start)
    }
    fn end(&self) -> Bound<&T> {
        Excluded(&self.end)
    }
}

impl<T> RangeArgument<T> for (Bound<T>, Bound<T>) {
    fn start(&self) -> Bound<&T> {
        match *self {
            (Included(ref start), _) => Included(start),
            (Excluded(ref start), _) => Excluded(start),
            (Unbounded, _)           => Unbounded,
        }
    }

    fn end(&self) -> Bound<&T> {
        match *self {
            (_, Included(ref end)) => Included(end),
            (_, Excluded(ref end)) => Excluded(end),
            (_, Unbounded)         => Unbounded,
        }
    }
}

impl<'a, T: ?Sized + 'a> RangeArgument<T> for (Bound<&'a T>, Bound<&'a T>) {
    fn start(&self) -> Bound<&T> {
        match *self {
            (Included(start), _) => Included(start),
            (Excluded(start), _) => Excluded(start),
            (Unbounded, _)       => Unbounded,
        }
    }

    fn end(&self) -> Bound<&T> {
        match *self {
            (_, Included(end)) => Included(end),
            (_, Excluded(end)) => Excluded(end),
            (_, Unbounded)     => Unbounded,
        }
    }
}
<commit_msg>make rangeargument methods non-default; simplify impl<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(feature = "collections_range",
            reason = "waiting for dust to settle on inclusive ranges",
            issue = "30877")]

//! Range syntax.

use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
use Bound::{self, Excluded, Included, Unbounded};

/// **RangeArgument** is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T: ?Sized> {
    /// Start index bound
    ///
    /// Return start value as a `Bound`
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(collections)]
    /// #![feature(collections_range)]
    /// #![feature(collections_bound)]
    ///
    /// extern crate collections;
    ///
    /// # fn main() {
    /// use collections::range::RangeArgument;
    /// use collections::Bound::*;
    ///
    /// assert_eq!((..10).start(), Unbounded);
    /// assert_eq!((3..10).start(), Included(&3));
    /// # }
    /// ```
    fn start(&self) -> Bound<&T>;

    /// End index bound
    ///
    /// Return end value as a `Bound`
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(collections)]
    /// #![feature(collections_range)]
    /// #![feature(collections_bound)]
    ///
    /// extern crate collections;
    ///
    /// # fn main() {
    /// use collections::range::RangeArgument;
    /// use collections::Bound::*;
    ///
    /// assert_eq!((3..).end(), Unbounded);
    /// assert_eq!((3..10).end(), Excluded(&10));
    /// # }
    /// ```
    fn end(&self) -> Bound<&T>;
}

// FIXME add inclusive ranges to RangeArgument

impl<T: ?Sized> RangeArgument<T> for RangeFull {
    fn start(&self) -> Bound<&T> {
        Unbounded
    }
    fn end(&self) -> Bound<&T> {
        Unbounded
    }
}

impl<T> RangeArgument<T> for RangeFrom<T> {
    fn start(&self) -> Bound<&T> {
        Included(&self.start)
    }
    fn end(&self) -> Bound<&T> {
        Unbounded
    }
}

impl<T> RangeArgument<T> for RangeTo<T> {
    fn start(&self) -> Bound<&T> {
        Unbounded
    }
    fn end(&self) -> Bound<&T> {
        Excluded(&self.end)
    }
}

impl<T> RangeArgument<T> for Range<T> {
    fn start(&self) -> Bound<&T> {
        Included(&self.start)
    }
    fn end(&self) -> Bound<&T> {
        Excluded(&self.end)
    }
}

impl<T> RangeArgument<T> for (Bound<T>, Bound<T>) {
    fn start(&self) -> Bound<&T> {
        match *self {
            (Included(ref start), _) => Included(start),
            (Excluded(ref start), _) => Excluded(start),
            (Unbounded, _)           => Unbounded,
        }
    }

    fn end(&self) -> Bound<&T> {
        match *self {
            (_, Included(ref end)) => Included(end),
            (_, Excluded(ref end)) => Excluded(end),
            (_, Unbounded)         => Unbounded,
        }
    }
}

impl<'a, T: ?Sized + 'a> RangeArgument<T> for (Bound<&'a T>, Bound<&'a T>) {
    fn start(&self) -> Bound<&T> {
        self.0
    }

    fn end(&self) -> Bound<&T> {
        self.1
    }
}
<|endoftext|>


<commit_before>import T = inst::T;

export min_value, max_value;
export min, max;
export add, sub, mul, div, rem;
export lt, le, eq, ne, ge, gt;
export is_positive, is_negative;
export is_nonpositive, is_nonnegative;
export range;
export compl;
export abs;
export parse_buf, from_str, to_str, str;

const min_value: T = -1 as T << (inst::bits - 1 as T);
const max_value: T = min_value - 1 as T;

pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }

pure fn add(x: T, y: T) -> T { x + y }
pure fn sub(x: T, y: T) -> T { x - y }
pure fn mul(x: T, y: T) -> T { x * y }
pure fn div(x: T, y: T) -> T { x / y }
pure fn rem(x: T, y: T) -> T { x % y }

pure fn lt(x: T, y: T) -> bool { x < y }
pure fn le(x: T, y: T) -> bool { x <= y }
pure fn eq(x: T, y: T) -> bool { x == y }
pure fn ne(x: T, y: T) -> bool { x != y }
pure fn ge(x: T, y: T) -> bool { x >= y }
pure fn gt(x: T, y: T) -> bool { x > y }

pure fn is_positive(x: T) -> bool { x > 0 as T }
pure fn is_negative(x: T) -> bool { x < 0 as T }
pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }

#[doc = "Iterate over the range [`lo`..`hi`)"]
fn range(lo: T, hi: T, it: fn(T)) {
    let mut i = lo;
    while i < hi { it(i); i += 1 as T; }
}

#[doc = "Computes the bitwise complement"]
pure fn compl(i: T) -> T {
    -1 as T ^ i
}

#[doc = "Computes the absolute value"]
// FIXME: abs should return an unsigned int (#2353)
pure fn abs(i: T) -> T {
    if is_negative(i) { -i } else { i }
}

#[doc = "
Parse a buffer of bytes

# Arguments

* buf - A byte buffer
* radix - The base of the number
"]
fn parse_buf(buf: [u8], radix: uint) -> option<T> {
    if vec::len(buf) == 0u { ret none; }
    let mut i = vec::len(buf) - 1u;
    let mut start = 0u;
    let mut power = 1 as T;

    if buf[0] == ('-' as u8) {
        power = -1 as T;
        start = 1u;
    }
    let mut n = 0 as T;
    loop {
        alt char::to_digit(buf[i] as char, radix) {
          some(d) { n += (d as T) * power; }
          none { ret none; }
        }
        power *= radix as T;
        if i <= start { ret some(n); }
        i -= 1u;
    };
}

#[doc = "Parse a string to an int"]
fn from_str(s: str) -> option<T> { parse_buf(str::bytes(s), 10u) }

#[doc = "Convert to a string in a given base"]
fn to_str(n: T, radix: uint) -> str {
    assert (0u < radix && radix <= 16u);
    ret if n < 0 as T {
            "-" + uint::to_str(-n as uint, radix)
        } else { uint::to_str(n as uint, radix) };
}

#[doc = "Convert to a string"]
fn str(i: T) -> str { ret to_str(i, 10u); }

// FIXME: Has alignment issues on windows
#[test]
#[ignore(cfg(target_os = "win32"))]
fn test_from_str() {
    assert from_str("0") == some(0 as T);
    assert from_str("3") == some(3 as T);
    assert from_str("10") == some(10 as T);
    assert from_str("123456789") == some(123456789 as T);
    assert from_str("00100") == some(100 as T);

    assert from_str("-1") == some(-1 as T);
    assert from_str("-3") == some(-3 as T);
    assert from_str("-10") == some(-10 as T);
    assert from_str("-123456789") == some(-123456789 as T);
    assert from_str("-00100") == some(-100 as T);

    assert from_str(" ") == none;
    assert from_str("x") == none;
}

// FIXME: Has alignment issues on windows
#[test]
#[ignore(cfg(target_os = "win32"))]
fn test_parse_buf() {
    import str::bytes;
    assert parse_buf(bytes("123"), 10u) == some(123 as T);
    assert parse_buf(bytes("1001"), 2u) == some(9 as T);
    assert parse_buf(bytes("123"), 8u) == some(83 as T);
    assert parse_buf(bytes("123"), 16u) == some(291 as T);
    assert parse_buf(bytes("ffff"), 16u) == some(65535 as T);
    assert parse_buf(bytes("FFFF"), 16u) == some(65535 as T);
    assert parse_buf(bytes("z"), 36u) == some(35 as T);
    assert parse_buf(bytes("Z"), 36u) == some(35 as T);

    assert parse_buf(bytes("-123"), 10u) == some(-123 as T);
    assert parse_buf(bytes("-1001"), 2u) == some(-9 as T);
    assert parse_buf(bytes("-123"), 8u) == some(-83 as T);
    assert parse_buf(bytes("-123"), 16u) == some(-291 as T);
    assert parse_buf(bytes("-ffff"), 16u) == some(-65535 as T);
    assert parse_buf(bytes("-FFFF"), 16u) == some(-65535 as T);
    assert parse_buf(bytes("-z"), 36u) == some(-35 as T);
    assert parse_buf(bytes("-Z"), 36u) == some(-35 as T);

    assert parse_buf(str::bytes("Z"), 35u) == none;
    assert parse_buf(str::bytes("-9"), 2u) == none;
}

#[test]
fn test_to_str() {
    import str::eq;
    assert (eq(to_str(0 as T, 10u), "0"));
    assert (eq(to_str(1 as T, 10u), "1"));
    assert (eq(to_str(-1 as T, 10u), "-1"));
    assert (eq(to_str(127 as T, 16u), "7f"));
    assert (eq(to_str(100 as T, 10u), "100"));
}
<commit_msg>core: Ignore more tests on more platforms<commit_after>import T = inst::T;

export min_value, max_value;
export min, max;
export add, sub, mul, div, rem;
export lt, le, eq, ne, ge, gt;
export is_positive, is_negative;
export is_nonpositive, is_nonnegative;
export range;
export compl;
export abs;
export parse_buf, from_str, to_str, str;

const min_value: T = -1 as T << (inst::bits - 1 as T);
const max_value: T = min_value - 1 as T;

pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }

pure fn add(x: T, y: T) -> T { x + y }
pure fn sub(x: T, y: T) -> T { x - y }
pure fn mul(x: T, y: T) -> T { x * y }
pure fn div(x: T, y: T) -> T { x / y }
pure fn rem(x: T, y: T) -> T { x % y }

pure fn lt(x: T, y: T) -> bool { x < y }
pure fn le(x: T, y: T) -> bool { x <= y }
pure fn eq(x: T, y: T) -> bool { x == y }
pure fn ne(x: T, y: T) -> bool { x != y }
pure fn ge(x: T, y: T) -> bool { x >= y }
pure fn gt(x: T, y: T) -> bool { x > y }

pure fn is_positive(x: T) -> bool { x > 0 as T }
pure fn is_negative(x: T) -> bool { x < 0 as T }
pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }

#[doc = "Iterate over the range [`lo`..`hi`)"]
fn range(lo: T, hi: T, it: fn(T)) {
    let mut i = lo;
    while i < hi { it(i); i += 1 as T; }
}

#[doc = "Computes the bitwise complement"]
pure fn compl(i: T) -> T {
    -1 as T ^ i
}

#[doc = "Computes the absolute value"]
// FIXME: abs should return an unsigned int (#2353)
pure fn abs(i: T) -> T {
    if is_negative(i) { -i } else { i }
}

#[doc = "
Parse a buffer of bytes

# Arguments

* buf - A byte buffer
* radix - The base of the number
"]
fn parse_buf(buf: [u8], radix: uint) -> option<T> {
    if vec::len(buf) == 0u { ret none; }
    let mut i = vec::len(buf) - 1u;
    let mut start = 0u;
    let mut power = 1 as T;

    if buf[0] == ('-' as u8) {
        power = -1 as T;
        start = 1u;
    }
    let mut n = 0 as T;
    loop {
        alt char::to_digit(buf[i] as char, radix) {
          some(d) { n += (d as T) * power; }
          none { ret none; }
        }
        power *= radix as T;
        if i <= start { ret some(n); }
        i -= 1u;
    };
}

#[doc = "Parse a string to an int"]
fn from_str(s: str) -> option<T> { parse_buf(str::bytes(s), 10u) }

#[doc = "Convert to a string in a given base"]
fn to_str(n: T, radix: uint) -> str {
    assert (0u < radix && radix <= 16u);
    ret if n < 0 as T {
            "-" + uint::to_str(-n as uint, radix)
        } else { uint::to_str(n as uint, radix) };
}

#[doc = "Convert to a string"]
fn str(i: T) -> str { ret to_str(i, 10u); }

// FIXME: Has alignment issues on windows and 32-bit linux
#[test]
#[ignore]
fn test_from_str() {
    assert from_str("0") == some(0 as T);
    assert from_str("3") == some(3 as T);
    assert from_str("10") == some(10 as T);
    assert from_str("123456789") == some(123456789 as T);
    assert from_str("00100") == some(100 as T);

    assert from_str("-1") == some(-1 as T);
    assert from_str("-3") == some(-3 as T);
    assert from_str("-10") == some(-10 as T);
    assert from_str("-123456789") == some(-123456789 as T);
    assert from_str("-00100") == some(-100 as T);

    assert from_str(" ") == none;
    assert from_str("x") == none;
}

// FIXME: Has alignment issues on windows and 32-bit linux
#[test]
#[ignore]
fn test_parse_buf() {
    import str::bytes;
    assert parse_buf(bytes("123"), 10u) == some(123 as T);
    assert parse_buf(bytes("1001"), 2u) == some(9 as T);
    assert parse_buf(bytes("123"), 8u) == some(83 as T);
    assert parse_buf(bytes("123"), 16u) == some(291 as T);
    assert parse_buf(bytes("ffff"), 16u) == some(65535 as T);
    assert parse_buf(bytes("FFFF"), 16u) == some(65535 as T);
    assert parse_buf(bytes("z"), 36u) == some(35 as T);
    assert parse_buf(bytes("Z"), 36u) == some(35 as T);

    assert parse_buf(bytes("-123"), 10u) == some(-123 as T);
    assert parse_buf(bytes("-1001"), 2u) == some(-9 as T);
    assert parse_buf(bytes("-123"), 8u) == some(-83 as T);
    assert parse_buf(bytes("-123"), 16u) == some(-291 as T);
    assert parse_buf(bytes("-ffff"), 16u) == some(-65535 as T);
    assert parse_buf(bytes("-FFFF"), 16u) == some(-65535 as T);
    assert parse_buf(bytes("-z"), 36u) == some(-35 as T);
    assert parse_buf(bytes("-Z"), 36u) == some(-35 as T);

    assert parse_buf(str::bytes("Z"), 35u) == none;
    assert parse_buf(str::bytes("-9"), 2u) == none;
}

#[test]
fn test_to_str() {
    import str::eq;
    assert (eq(to_str(0 as T, 10u), "0"));
    assert (eq(to_str(1 as T, 10u), "1"));
    assert (eq(to_str(-1 as T, 10u), "-1"));
    assert (eq(to_str(127 as T, 16u), "7f"));
    assert (eq(to_str(100 as T, 10u), "100"));
}
<|endoftext|>


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

use cmp;
use mem;

const LO_U64: u64 = 0x0101010101010101;
const HI_U64: u64 = 0x8080808080808080;

// use truncation
const LO_USIZE: usize = LO_U64 as usize;
const HI_USIZE: usize = HI_U64 as usize;

/// Return `true` if `x` contains any zero byte.
///
/// From *Matters Computational*, J. Arndt
///
/// "The idea is to subtract one from each of the bytes and then look for
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
fn contains_zero_byte(x: usize) -> bool {
    x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}

#[cfg(target_pointer_width = "16")]
#[inline]
fn repeat_byte(b: u8) -> usize {
    (b as usize) << 8 | b as usize
}

#[cfg(not(target_pointer_width = "16"))]
#[inline]
fn repeat_byte(b: u8) -> usize {
    (b as usize) * (::usize::MAX / 255)
}

/// Return the first index matching the byte `x` in `text`.
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned initial part, before the first word aligned address in text
    // - body, scan by 2 words at a time
    // - the last remaining part, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    // search up to an aligned boundary
    let mut offset = ptr.align_offset(usize_bytes);
    if offset > 0 {
        offset = cmp::min(offset, len);
        if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
            return Some(index);
        }
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    if len >= 2 * usize_bytes {
        while offset <= len - 2 * usize_bytes {
            unsafe {
                let u = *(ptr.offset(offset as isize) as *const usize);
                let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);

                // break if there is a matching byte
                let zu = contains_zero_byte(u ^ repeated_x);
                let zv = contains_zero_byte(v ^ repeated_x);
                if zu || zv {
                    break;
                }
            }
            offset += usize_bytes * 2;
        }
    }

    // find the byte after the point the body loop stopped
    text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
}

/// Return the last index matching the byte `x` in `text`.
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned tail, after the last word aligned address in text
    // - body, scan by 2 words at a time
    // - the first remaining bytes, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    // search to an aligned boundary
    let end_align = (ptr as usize + len) & (usize_bytes - 1);
    let mut offset;
    if end_align > 0 {
        offset = if end_align >= len { 0 } else { len - end_align };
        if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
            return Some(offset + index);
        }
    } else {
        offset = len;
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    while offset >= 2 * usize_bytes {
        unsafe {
            let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
            let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);

            // break if there is a matching byte
            let zu = contains_zero_byte(u ^ repeated_x);
            let zv = contains_zero_byte(v ^ repeated_x);
            if zu || zv {
                break;
            }
        }
        offset -= 2 * usize_bytes;
    }

    // find the byte before the point the body loop stopped
    text[..offset].iter().rposition(|elt| *elt == x)
}
<commit_msg>Auto merge of #52744 - RalfJung:align_offset, r=Kimundi<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// Original implementation taken from rust-memchr
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch

use cmp;
use mem;

const LO_U64: u64 = 0x0101010101010101;
const HI_U64: u64 = 0x8080808080808080;

// use truncation
const LO_USIZE: usize = LO_U64 as usize;
const HI_USIZE: usize = HI_U64 as usize;

/// Return `true` if `x` contains any zero byte.
///
/// From *Matters Computational*, J. Arndt
///
/// "The idea is to subtract one from each of the bytes and then look for
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
fn contains_zero_byte(x: usize) -> bool {
    x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}

#[cfg(target_pointer_width = "16")]
#[inline]
fn repeat_byte(b: u8) -> usize {
    (b as usize) << 8 | b as usize
}

#[cfg(not(target_pointer_width = "16"))]
#[inline]
fn repeat_byte(b: u8) -> usize {
    (b as usize) * (::usize::MAX / 255)
}

/// Return the first index matching the byte `x` in `text`.
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned initial part, before the first word aligned address in text
    // - body, scan by 2 words at a time
    // - the last remaining part, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    // search up to an aligned boundary
    let mut offset = ptr.align_offset(usize_bytes);
    if offset > 0 {
        offset = cmp::min(offset, len);
        if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
            return Some(index);
        }
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    if len >= 2 * usize_bytes {
        while offset <= len - 2 * usize_bytes {
            unsafe {
                let u = *(ptr.offset(offset as isize) as *const usize);
                let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);

                // break if there is a matching byte
                let zu = contains_zero_byte(u ^ repeated_x);
                let zv = contains_zero_byte(v ^ repeated_x);
                if zu || zv {
                    break;
                }
            }
            offset += usize_bytes * 2;
        }
    }

    // find the byte after the point the body loop stopped
    text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
}

/// Return the last index matching the byte `x` in `text`.
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
    // Scan for a single byte value by reading two `usize` words at a time.
    //
    // Split `text` in three parts
    // - unaligned tail, after the last word aligned address in text
    // - body, scan by 2 words at a time
    // - the first remaining bytes, < 2 word size
    let len = text.len();
    let ptr = text.as_ptr();
    let usize_bytes = mem::size_of::<usize>();

    let mut offset = {
        // We call this just to obtain the length of the suffix
        let (_, _, suffix) = unsafe { text.align_to::<usize>() };
        len - suffix.len()
    };
    if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
        return Some(offset + index);
    }

    // search the body of the text
    let repeated_x = repeat_byte(x);

    while offset >= 2 * usize_bytes {
        unsafe {
            let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
            let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);

            // break if there is a matching byte
            let zu = contains_zero_byte(u ^ repeated_x);
            let zv = contains_zero_byte(v ^ repeated_x);
            if zu || zv {
                break;
            }
        }
        offset -= 2 * usize_bytes;
    }

    // find the byte before the point the body loop stopped
    text[..offset].iter().rposition(|elt| *elt == x)
}
<|endoftext|>


<commit_before>use crate::types::Type;
use crate::{errmsg_to_string, ffi};
use std::error;
use std::fmt;
use std::os::raw::c_int;
use std::path::PathBuf;
use std::str;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was
    /// configured to allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// Error when the value of a particular column is requested, but it cannot
    /// be converted to the requested Rust type.
    FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync>),

    /// Error when SQLite gives us an integral value outside the range of the
    /// requested type (e.g., trying to get the value 1000 into a `u8`).
    /// The associated `usize` is the column index,
    /// and the associated `i64` is the value returned by SQLite.
    IntegralValueOutOfRange(usize, i64),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained
    /// an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not
    /// present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g.,
    /// for `query_row`) did not return any.
    QueryReturnedNoRows,

    /// Error when the value of a particular column is requested, but the index
    /// is out of range for the statement.
    InvalidColumnIndex(usize),

    /// Error when the value of a named column is requested, but no column
    /// matches the name for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type
    /// of the result in that column cannot be converted to the requested
    /// Rust type.
    InvalidColumnType(usize, String, Type),

    /// Error when a query that was expected to insert one row did not insert
    /// any or insert many.
    StatementChangedRows(usize),

    /// Error returned by `functions::Context::get` when the function argument
    /// cannot be converted to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType(usize, Type),
    /// Error returned by `vtab::Values::get` when the filter argument cannot
    /// be converted to the requested type.
    #[cfg(feature = "vtab")]
    InvalidFilterParameterType(usize, Type),

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<dyn error::Error + Send + Sync>),

    /// Error available for the implementors of the `ToSql` trait.
    ToSqlConversionFailure(Box<dyn error::Error + Send + Sync>),

    /// Error when the SQL is not a `SELECT`, is not read-only.
    InvalidQuery,

    /// An error case available for implementors of custom modules (e.g.,
    /// `create_module`).
    #[cfg(feature = "vtab")]
    #[allow(dead_code)]
    ModuleError(String),

    #[cfg(feature = "functions")]
    UnwindingPanic,

    /// An error returned when `Context::get_aux` attempts to retrieve data
    /// of a different type than what had been stored using `Context::set_aux`.
    #[cfg(feature = "functions")]
    GetAuxWrongType,
}

impl PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
            (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
            (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
                i1 == i2 && n1 == n2
            }
            (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
            (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
            (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
            (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
            (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
            (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
            (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
            (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
            (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
                i1 == i2 && t1 == t2 && n1 == n2
            }
            (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
            #[cfg(feature = "functions")]
            (
                Error::InvalidFunctionParameterType(i1, t1),
                Error::InvalidFunctionParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            #[cfg(feature = "vtab")]
            (
                Error::InvalidFilterParameterType(i1, t1),
                Error::InvalidFilterParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            (Error::InvalidQuery, Error::InvalidQuery) => true,
            #[cfg(feature = "vtab")]
            (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
            #[cfg(feature = "functions")]
            (Error::UnwindingPanic, Error::UnwindingPanic) => true,
            #[cfg(feature = "functions")]
            (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
            (_, _) => false,
        }
    }
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8Error(err)
    }
}

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => write!(
                f,
                "SQLite was compiled or configured for single-threaded use only"
            ),
            Error::FromSqlConversionFailure(i, ref t, ref err) => write!(
                f,
                "Conversion error from type {} at index: {}, {}",
                t, i, err
            ),
            Error::IntegralValueOutOfRange(col, val) => {
                write!(f, "Integer {} out of range at index {}", val, col)
            }
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType(i, ref name, ref t) => write!(
                f,
                "Invalid column type {} at index: {}, name: {}",
                t, i, name
            ),
            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(i, ref t) => {
                write!(f, "Invalid function parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(i, ref t) => {
                write!(f, "Invalid filter parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
            Error::ToSqlConversionFailure(ref err) => err.fmt(f),
            Error::InvalidQuery => write!(f, "Query is not read-only"),
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => write!(f, "{}", desc),
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => write!(f, "unwinding panic"),
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(_, _, ref err) => err.description(),
            Error::IntegralValueOutOfRange(_, _) => "integral value out of range of requested type",
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType(_, _, _) => "invalid column type",
            Error::StatementChangedRows(_) => "query inserted zero or more than one row",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(_, _) => "invalid filter parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
            Error::ToSqlConversionFailure(ref err) => err.description(),
            Error::InvalidQuery => "query is not read-only",
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => desc,
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => "unwinding panic",
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => "get_aux called with wrong type",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::IntegralValueOutOfRange(_, _)
            | Error::SqliteSingleThreadedMode
            | Error::InvalidParameterName(_)
            | Error::ExecuteReturnedResults
            | Error::QueryReturnedNoRows
            | Error::InvalidColumnIndex(_)
            | Error::InvalidColumnName(_)
            | Error::InvalidColumnType(_, _, _)
            | Error::InvalidPath(_)
            | Error::StatementChangedRows(_)
            | Error::InvalidQuery => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => None,
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(_, _) => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),

            Error::FromSqlConversionFailure(_, _, ref err)
            | Error::ToSqlConversionFailure(ref err) => Some(&**err),

            #[cfg(feature = "vtab")]
            Error::ModuleError(_) => None,

            #[cfg(feature = "functions")]
            Error::UnwindingPanic => None,

            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => None,
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}

macro_rules! check {
    ($funcall:expr) => {{
        let rc = $funcall;
        if rc != crate::ffi::SQLITE_OK {
            return Err(crate::error::error_from_sqlite_code(rc, None).into());
        }
    }};
}
<commit_msg>Conversion from FromSqlError to Error<commit_after>use crate::types::Type;
use crate::types::FromSqlError;
use crate::{errmsg_to_string, ffi};
use std::error;
use std::fmt;
use std::os::raw::c_int;
use std::path::PathBuf;
use std::str;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was
    /// configured to allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// Error when the value of a particular column is requested, but it cannot
    /// be converted to the requested Rust type.
    FromSqlConversionFailure(usize, Type, Box<dyn error::Error + Send + Sync>),

    /// Error when SQLite gives us an integral value outside the range of the
    /// requested type (e.g., trying to get the value 1000 into a `u8`).
    /// The associated `usize` is the column index,
    /// and the associated `i64` is the value returned by SQLite.
    IntegralValueOutOfRange(usize, i64),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained
    /// an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not
    /// present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g.,
    /// for `query_row`) did not return any.
    QueryReturnedNoRows,

    /// Error when the value of a particular column is requested, but the index
    /// is out of range for the statement.
    InvalidColumnIndex(usize),

    /// Error when the value of a named column is requested, but no column
    /// matches the name for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type
    /// of the result in that column cannot be converted to the requested
    /// Rust type.
    InvalidColumnType(usize, String, Type),

    /// Error when a query that was expected to insert one row did not insert
    /// any or insert many.
    StatementChangedRows(usize),

    /// Error returned by `functions::Context::get` when the function argument
    /// cannot be converted to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType(usize, Type),
    /// Error returned by `vtab::Values::get` when the filter argument cannot
    /// be converted to the requested type.
    #[cfg(feature = "vtab")]
    InvalidFilterParameterType(usize, Type),

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<dyn error::Error + Send + Sync>),

    /// Error available for the implementors of the `ToSql` trait.
    ToSqlConversionFailure(Box<dyn error::Error + Send + Sync>),

    /// Error when the SQL is not a `SELECT`, is not read-only.
    InvalidQuery,

    /// An error case available for implementors of custom modules (e.g.,
    /// `create_module`).
    #[cfg(feature = "vtab")]
    #[allow(dead_code)]
    ModuleError(String),

    #[cfg(feature = "functions")]
    UnwindingPanic,

    /// An error returned when `Context::get_aux` attempts to retrieve data
    /// of a different type than what had been stored using `Context::set_aux`.
    #[cfg(feature = "functions")]
    GetAuxWrongType,
}

impl PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        match (self, other) {
            (Error::SqliteFailure(e1, s1), Error::SqliteFailure(e2, s2)) => e1 == e2 && s1 == s2,
            (Error::SqliteSingleThreadedMode, Error::SqliteSingleThreadedMode) => true,
            (Error::IntegralValueOutOfRange(i1, n1), Error::IntegralValueOutOfRange(i2, n2)) => {
                i1 == i2 && n1 == n2
            }
            (Error::Utf8Error(e1), Error::Utf8Error(e2)) => e1 == e2,
            (Error::NulError(e1), Error::NulError(e2)) => e1 == e2,
            (Error::InvalidParameterName(n1), Error::InvalidParameterName(n2)) => n1 == n2,
            (Error::InvalidPath(p1), Error::InvalidPath(p2)) => p1 == p2,
            (Error::ExecuteReturnedResults, Error::ExecuteReturnedResults) => true,
            (Error::QueryReturnedNoRows, Error::QueryReturnedNoRows) => true,
            (Error::InvalidColumnIndex(i1), Error::InvalidColumnIndex(i2)) => i1 == i2,
            (Error::InvalidColumnName(n1), Error::InvalidColumnName(n2)) => n1 == n2,
            (Error::InvalidColumnType(i1, n1, t1), Error::InvalidColumnType(i2, n2, t2)) => {
                i1 == i2 && t1 == t2 && n1 == n2
            }
            (Error::StatementChangedRows(n1), Error::StatementChangedRows(n2)) => n1 == n2,
            #[cfg(feature = "functions")]
            (
                Error::InvalidFunctionParameterType(i1, t1),
                Error::InvalidFunctionParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            #[cfg(feature = "vtab")]
            (
                Error::InvalidFilterParameterType(i1, t1),
                Error::InvalidFilterParameterType(i2, t2),
            ) => i1 == i2 && t1 == t2,
            (Error::InvalidQuery, Error::InvalidQuery) => true,
            #[cfg(feature = "vtab")]
            (Error::ModuleError(s1), Error::ModuleError(s2)) => s1 == s2,
            #[cfg(feature = "functions")]
            (Error::UnwindingPanic, Error::UnwindingPanic) => true,
            #[cfg(feature = "functions")]
            (Error::GetAuxWrongType, Error::GetAuxWrongType) => true,
            (_, _) => false,
        }
    }
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8Error(err)
    }
}

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

const UNKNOWN_COLUMN: usize = std::usize::MAX;

/// The conversion isn't precise, but it's convenient to have it
/// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
impl From<FromSqlError> for Error {
    fn from(err: FromSqlError) -> Error {
        // The error type requires index and type fields, but they aren't known in this context.
        match err {
            FromSqlError::OutOfRange(val) => Error::IntegralValueOutOfRange(UNKNOWN_COLUMN, val),
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(s) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
            }
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(s) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Blob, Box::new(err))
            }
            FromSqlError::Other(source) => {
                Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, source)
            }
            _ => Error::FromSqlConversionFailure(UNKNOWN_COLUMN, Type::Null, Box::new(err)),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => write!(
                f,
                "SQLite was compiled or configured for single-threaded use only"
            ),
            Error::FromSqlConversionFailure(i, ref t, ref err) => if i != UNKNOWN_COLUMN {
                write!(
                    f,
                    "Conversion error from type {} at index: {}, {}",
                    t, i, err
                )
            } else {
                err.fmt(f)
            },
            Error::IntegralValueOutOfRange(col, val) => if col != UNKNOWN_COLUMN {
                write!(f, "Integer {} out of range at index {}", val, col)
            } else {
                write!(f, "Integer {} out of range", val)
            },
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType(i, ref name, ref t) => write!(
                f,
                "Invalid column type {} at index: {}, name: {}",
                t, i, name
            ),
            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(i, ref t) => {
                write!(f, "Invalid function parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(i, ref t) => {
                write!(f, "Invalid filter parameter type {} at index {}", t, i)
            }
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
            Error::ToSqlConversionFailure(ref err) => err.fmt(f),
            Error::InvalidQuery => write!(f, "Query is not read-only"),
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => write!(f, "{}", desc),
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => write!(f, "unwinding panic"),
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(_, _, ref err) => err.description(),
            Error::IntegralValueOutOfRange(_, _) => "integral value out of range of requested type",
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType(_, _, _) => "invalid column type",
            Error::StatementChangedRows(_) => "query inserted zero or more than one row",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(_, _) => "invalid filter parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
            Error::ToSqlConversionFailure(ref err) => err.description(),
            Error::InvalidQuery => "query is not read-only",
            #[cfg(feature = "vtab")]
            Error::ModuleError(ref desc) => desc,
            #[cfg(feature = "functions")]
            Error::UnwindingPanic => "unwinding panic",
            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => "get_aux called with wrong type",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::IntegralValueOutOfRange(_, _)
            | Error::SqliteSingleThreadedMode
            | Error::InvalidParameterName(_)
            | Error::ExecuteReturnedResults
            | Error::QueryReturnedNoRows
            | Error::InvalidColumnIndex(_)
            | Error::InvalidColumnName(_)
            | Error::InvalidColumnType(_, _, _)
            | Error::InvalidPath(_)
            | Error::StatementChangedRows(_)
            | Error::InvalidQuery => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType(_, _) => None,
            #[cfg(feature = "vtab")]
            Error::InvalidFilterParameterType(_, _) => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),

            Error::FromSqlConversionFailure(_, _, ref err)
            | Error::ToSqlConversionFailure(ref err) => Some(&**err),

            #[cfg(feature = "vtab")]
            Error::ModuleError(_) => None,

            #[cfg(feature = "functions")]
            Error::UnwindingPanic => None,

            #[cfg(feature = "functions")]
            Error::GetAuxWrongType => None,
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}

macro_rules! check {
    ($funcall:expr) => {{
        let rc = $funcall;
        if rc != crate::ffi::SQLITE_OK {
            return Err(crate::error::error_from_sqlite_code(rc, None).into());
        }
    }};
}
<|endoftext|>


<commit_before>use libc::{c_uint, c_void};

use std::error::{Error, FromError};
use std::ops::Index;
use std::num::Int;
use std::ptr;

pub struct H5ErrorFrame {
    pub desc: String,
    pub func: String,
    pub major: String,
    pub minor: String
}

impl H5ErrorFrame {
    pub fn description(&self) -> &str {
        self.desc.as_slice()
    }

    pub fn detail(&self) -> Option<String> {
        Some(format!("Error in {}(): {} [{}: {}]",
             self.func, self.desc, self.major, self.minor).clone())
    }
}

pub fn silence_errors() {
    use ffi::h5e::{H5Eset_auto2, H5E_DEFAULT};

    h5lock! { unsafe {
        H5Eset_auto2(H5E_DEFAULT, None, ptr::null_mut::<c_void>())
    }};
}

#[test]
fn test_error_stack_query() {
    use ffi::types::hid_t;
    use ffi::h5p::{H5Pcreate, H5Pclose, H5P_CLS_ROOT_ID};

    let cls_id = *H5P_CLS_ROOT_ID;
    let mut plist_id: hid_t = 0;

    silence_errors();

    let result_no_error = h5lock! { unsafe {
        plist_id = H5Pcreate(cls_id);
        H5Pclose(plist_id);
        H5ErrorStack::query()
    }};
    assert!(result_no_error.ok().unwrap().is_none());

    let result_error = h5lock! {unsafe {
        H5Pclose(plist_id);
        H5ErrorStack::query()
    }};
    let stack = result_error.ok().unwrap().unwrap();
    assert_eq!(stack.description(), "can't close");
    assert_eq!(stack.detail().unwrap().as_slice(),
               "Error in H5Pclose(): can't close [Property lists: Unable to free object]");

    assert_eq!(stack.len(), 3);
    assert!(!stack.is_empty());

    assert_eq!(stack[0].description(), "can't close");
    assert_eq!(stack[0].detail().unwrap().as_slice(),
               "Error in H5Pclose(): can't close \
                [Property lists: Unable to free object]");

    assert_eq!(stack[1].description(), "can't decrement ID ref count");
    assert_eq!(stack[1].detail().unwrap().as_slice(),
               "Error in H5I_dec_app_ref(): can't decrement ID ref count \
                [Object atom: Unable to decrement reference count]");

    assert_eq!(stack[2].description(), "can't locate ID");
    assert_eq!(stack[2].detail().unwrap().as_slice(),
               "Error in H5I_dec_ref(): can't locate ID \
                [Object atom: Unable to find atom information (already closed?)]");

    let empty_stack = H5ErrorStack::new();
    assert!(empty_stack.is_empty());
    assert_eq!(empty_stack.len(), 0);
}

pub struct H5ErrorStack {
    frames: Vec<H5ErrorFrame>
}

impl Index<usize> for H5ErrorStack {
    type Output = H5ErrorFrame;

    fn index<'a>(&'a self, index: &usize) -> &'a H5ErrorFrame {
        &self.frames[*index]
    }
}

impl H5ErrorStack {
    // This low-level function is not thread-safe and has to be synchronized by the user
    pub fn query() -> H5Result<Option<H5ErrorStack>> {
        use ffi::types::herr_t;
        use ffi::util::{get_h5_str, str_from_c};
        use ffi::h5e::{H5Ewalk2, H5Eget_msg, H5E_error2_t, H5E_type_t, H5E_WALK_DOWNWARD,
                       H5Eget_current_stack, H5Eclose_stack};

        struct CallbackData {
            stack: H5ErrorStack,
            err: Option<H5Error>,
        }

        extern fn callback(_: c_uint, err_desc: *const H5E_error2_t, data: *mut c_void) -> herr_t {
            unsafe {
                let data = &mut *(data as *mut CallbackData);
                if data.err.is_some() {
                    return 0;
                }
                let closure = |&: e: H5E_error2_t| -> H5Result<H5ErrorFrame> {
                    let (desc, func) = (str_from_c(e.desc), str_from_c(e.func_name));
                    let major = try!(get_h5_str(|m, s| {
                        H5Eget_msg(e.maj_num, ptr::null_mut::<H5E_type_t>(), m, s)
                    }));
                    let minor = try!(get_h5_str(|m, s| {
                        H5Eget_msg(e.min_num, ptr::null_mut::<H5E_type_t>(), m, s)
                    }));
                    Ok(H5ErrorFrame { desc: desc, func: func, major: major, minor: minor })
                };
                match closure(*err_desc) {
                    Ok(frame) => { data.stack.push(frame); 0 },
                    Err(err)  => { data.err = Some(FromError::from_error(err)); 0 },
                }
            }
        }

        let mut data = CallbackData { stack: H5ErrorStack::new(), err: None };
        let data_ptr: *mut c_void = &mut data as *mut _ as *mut c_void;

        // HDF5 bug: H5Eget_msg() may corrupt the current stack, so copy it first
        unsafe {
            let stack_id = H5Eget_current_stack();
            ensure!(stack_id >= 0, "failed to copy the current error stack");
            H5Ewalk2(stack_id, H5E_WALK_DOWNWARD, Some(callback), data_ptr);
            H5Eclose_stack(stack_id)
        };

        match (data.err, data.stack.is_empty()) {
            (Some(err), _) => Err(err),
            (None, false)  => Ok(Some(data.stack)),
            (None, true)   => Ok(None),
        }
    }

    pub fn new() -> H5ErrorStack {
        H5ErrorStack { frames: Vec::new() }
    }

    pub fn len(&self) -> usize {
        self.frames.len()
    }

    pub fn push(&mut self, frame: H5ErrorFrame) {
        self.frames.push(frame)
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn top(&self) -> Option<&H5ErrorFrame> {
        match !self.is_empty() {
            false => None,
            true  => Some(&self.frames[0]),
        }
    }

    pub fn description(&self) -> &str {
        match self.top() {
            None        => "unknown library error",
            Some(frame) => frame.description(),
        }
    }

    pub fn detail(&self) -> Option<String> {
        match self.top() {
            None        => None,
            Some(frame) => frame.detail(),
        }
    }
}

pub enum H5Error {
    LibraryError(H5ErrorStack),
    InternalError(&'static str),
}

pub type H5Result<T> = Result<T, H5Error>;

impl H5Error {
    pub fn query() -> Option<H5Error> {
        match H5ErrorStack::query() {
            Err(err)        => Some(FromError::from_error(err)),
            Ok(Some(stack)) => Some(H5Error::LibraryError(stack)),
            Ok(None)        => None,
        }
    }
}

impl FromError<&'static str> for H5Error {
    fn from_error(desc: &'static str) -> H5Error {
        H5Error::InternalError(desc)
    }
}

impl Error for H5Error {
    fn description(&self) -> &str {
        match *self {
            H5Error::InternalError(desc)     => desc,
            H5Error::LibraryError(ref stack) => stack.description(),
        }
    }

    fn detail(&self) -> Option<String> {
        match *self {
            H5Error::InternalError(_)        => None,
            H5Error::LibraryError(ref stack) => stack.detail()
        }
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

#[test]
fn test_h5check() {
    use ffi::h5p::{H5Pcreate, H5Pclose, H5P_CLS_ROOT_ID};

    silence_errors();

    let plist_id = h5lock! {
        unsafe { H5Pcreate(*H5P_CLS_ROOT_ID) }
    };

    let result_no_error = h5lock! {
        h5check(unsafe { H5Pclose(plist_id) })
    };
    assert!(result_no_error.is_ok());

    let result_error = h5lock! {
        h5check(unsafe { H5Pclose(plist_id) })
    };
    assert!(result_error.is_err());
}

pub fn h5check<T>(value: T) -> H5Result<T> where T: Int,
{
    let min_value: T = Int::min_value();
    let zero:      T = Int::zero();

    let maybe_error = if min_value < zero {
        value < zero
    } else {
        value == zero
    };

    match maybe_error {
        false => Ok(value),
        true  => match H5Error::query() {
            None       => Ok(value),
            Some(err)  => Err(FromError::from_error(err)),
        },
    }
}

#[test]
fn test_h5try() {
    use ffi::types::herr_t;
    use ffi::h5p::{H5Pcreate, H5Pclose, H5P_CLS_ROOT_ID};

    silence_errors();

    fn f1() -> H5Result<herr_t> {
        let plist_id = h5try!(H5Pcreate(*H5P_CLS_ROOT_ID));
        h5try!(H5Pclose(plist_id));
        Ok(100)
    }

    let result1 = f1();
    assert!(result1.is_ok());
    assert_eq!(result1.ok().unwrap(), 100);

    fn f2() -> H5Result<herr_t> {
        let plist_id = h5try!(H5Pcreate(*H5P_CLS_ROOT_ID));
        h5try!(H5Pclose(plist_id));
        h5try!(H5Pclose(plist_id));
        Ok(100)
    }

    let result2 = f2();
    assert!(result2.is_err());
}

<commit_msg>Fix the sync in a test<commit_after>use libc::{c_uint, c_void};

use std::error::{Error, FromError};
use std::ops::Index;
use std::num::Int;
use std::ptr;

pub struct H5ErrorFrame {
    pub desc: String,
    pub func: String,
    pub major: String,
    pub minor: String
}

impl H5ErrorFrame {
    pub fn description(&self) -> &str {
        self.desc.as_slice()
    }

    pub fn detail(&self) -> Option<String> {
        Some(format!("Error in {}(): {} [{}: {}]",
             self.func, self.desc, self.major, self.minor).clone())
    }
}

pub fn silence_errors() {
    use ffi::h5e::{H5Eset_auto2, H5E_DEFAULT};

    h5lock! { unsafe {
        H5Eset_auto2(H5E_DEFAULT, None, ptr::null_mut::<c_void>())
    }};
}

#[test]
fn test_error_stack_query() {
    use ffi::h5p::{H5Pcreate, H5Pclose, H5P_CLS_ROOT_ID};

    silence_errors();

    let result_no_error = h5lock! { unsafe {
        let plist_id = H5Pcreate(*H5P_CLS_ROOT_ID);
        H5Pclose(plist_id);
        H5ErrorStack::query()
    }};
    assert!(result_no_error.ok().unwrap().is_none());

    let result_error = h5lock! {unsafe {
        let plist_id = H5Pcreate(*H5P_CLS_ROOT_ID);
        H5Pclose(plist_id);
        H5Pclose(plist_id);
        H5ErrorStack::query()
    }};
    let stack = result_error.ok().unwrap().unwrap();
    assert_eq!(stack.description(), "can't close");
    assert_eq!(stack.detail().unwrap().as_slice(),
               "Error in H5Pclose(): can't close [Property lists: Unable to free object]");

    assert_eq!(stack.len(), 3);
    assert!(!stack.is_empty());

    assert_eq!(stack[0].description(), "can't close");
    assert_eq!(stack[0].detail().unwrap().as_slice(),
               "Error in H5Pclose(): can't close \
                [Property lists: Unable to free object]");

    assert_eq!(stack[1].description(), "can't decrement ID ref count");
    assert_eq!(stack[1].detail().unwrap().as_slice(),
               "Error in H5I_dec_app_ref(): can't decrement ID ref count \
                [Object atom: Unable to decrement reference count]");

    assert_eq!(stack[2].description(), "can't locate ID");
    assert_eq!(stack[2].detail().unwrap().as_slice(),
               "Error in H5I_dec_ref(): can't locate ID \
                [Object atom: Unable to find atom information (already closed?)]");

    let empty_stack = H5ErrorStack::new();
    assert!(empty_stack.is_empty());
    assert_eq!(empty_stack.len(), 0);
}

pub struct H5ErrorStack {
    frames: Vec<H5ErrorFrame>
}

impl Index<usize> for H5ErrorStack {
    type Output = H5ErrorFrame;

    fn index<'a>(&'a self, index: &usize) -> &'a H5ErrorFrame {
        &self.frames[*index]
    }
}

impl H5ErrorStack {
    // This low-level function is not thread-safe and has to be synchronized by the user
    pub fn query() -> H5Result<Option<H5ErrorStack>> {
        use ffi::types::herr_t;
        use ffi::util::{get_h5_str, str_from_c};
        use ffi::h5e::{H5Ewalk2, H5Eget_msg, H5E_error2_t, H5E_type_t, H5E_WALK_DOWNWARD,
                       H5Eget_current_stack, H5Eclose_stack};

        struct CallbackData {
            stack: H5ErrorStack,
            err: Option<H5Error>,
        }

        extern fn callback(_: c_uint, err_desc: *const H5E_error2_t, data: *mut c_void) -> herr_t {
            unsafe {
                let data = &mut *(data as *mut CallbackData);
                if data.err.is_some() {
                    return 0;
                }
                let closure = |&: e: H5E_error2_t| -> H5Result<H5ErrorFrame> {
                    let (desc, func) = (str_from_c(e.desc), str_from_c(e.func_name));
                    let major = try!(get_h5_str(|m, s| {
                        H5Eget_msg(e.maj_num, ptr::null_mut::<H5E_type_t>(), m, s)
                    }));
                    let minor = try!(get_h5_str(|m, s| {
                        H5Eget_msg(e.min_num, ptr::null_mut::<H5E_type_t>(), m, s)
                    }));
                    Ok(H5ErrorFrame { desc: desc, func: func, major: major, minor: minor })
                };
                match closure(*err_desc) {
                    Ok(frame) => { data.stack.push(frame); 0 },
                    Err(err)  => { data.err = Some(FromError::from_error(err)); 0 },
                }
            }
        }

        let mut data = CallbackData { stack: H5ErrorStack::new(), err: None };
        let data_ptr: *mut c_void = &mut data as *mut _ as *mut c_void;

        // HDF5 bug: H5Eget_msg() may corrupt the current stack, so copy it first
        unsafe {
            let stack_id = H5Eget_current_stack();
            ensure!(stack_id >= 0, "failed to copy the current error stack");
            H5Ewalk2(stack_id, H5E_WALK_DOWNWARD, Some(callback), data_ptr);
            H5Eclose_stack(stack_id)
        };

        match (data.err, data.stack.is_empty()) {
            (Some(err), _) => Err(err),
            (None, false)  => Ok(Some(data.stack)),
            (None, true)   => Ok(None),
        }
    }

    pub fn new() -> H5ErrorStack {
        H5ErrorStack { frames: Vec::new() }
    }

    pub fn len(&self) -> usize {
        self.frames.len()
    }

    pub fn push(&mut self, frame: H5ErrorFrame) {
        self.frames.push(frame)
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn top(&self) -> Option<&H5ErrorFrame> {
        match !self.is_empty() {
            false => None,
            true  => Some(&self.frames[0]),
        }
    }

    pub fn description(&self) -> &str {
        match self.top() {
            None        => "unknown library error",
            Some(frame) => frame.description(),
        }
    }

    pub fn detail(&self) -> Option<String> {
        match self.top() {
            None        => None,
            Some(frame) => frame.detail(),
        }
    }
}

pub enum H5Error {
    LibraryError(H5ErrorStack),
    InternalError(&'static str),
}

pub type H5Result<T> = Result<T, H5Error>;

impl H5Error {
    pub fn query() -> Option<H5Error> {
        match H5ErrorStack::query() {
            Err(err)        => Some(FromError::from_error(err)),
            Ok(Some(stack)) => Some(H5Error::LibraryError(stack)),
            Ok(None)        => None,
        }
    }
}

impl FromError<&'static str> for H5Error {
    fn from_error(desc: &'static str) -> H5Error {
        H5Error::InternalError(desc)
    }
}

impl Error for H5Error {
    fn description(&self) -> &str {
        match *self {
            H5Error::InternalError(desc)     => desc,
            H5Error::LibraryError(ref stack) => stack.description(),
        }
    }

    fn detail(&self) -> Option<String> {
        match *self {
            H5Error::InternalError(_)        => None,
            H5Error::LibraryError(ref stack) => stack.detail()
        }
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

#[test]
fn test_h5check() {
    use ffi::h5p::{H5Pcreate, H5Pclose, H5P_CLS_ROOT_ID};

    silence_errors();

    let plist_id = h5lock! {
        unsafe { H5Pcreate(*H5P_CLS_ROOT_ID) }
    };

    let result_no_error = h5lock! {
        h5check(unsafe { H5Pclose(plist_id) })
    };
    assert!(result_no_error.is_ok());

    let result_error = h5lock! {
        h5check(unsafe { H5Pclose(plist_id) })
    };
    assert!(result_error.is_err());
}

pub fn h5check<T>(value: T) -> H5Result<T> where T: Int,
{
    let min_value: T = Int::min_value();
    let zero:      T = Int::zero();

    let maybe_error = if min_value < zero {
        value < zero
    } else {
        value == zero
    };

    match maybe_error {
        false => Ok(value),
        true  => match H5Error::query() {
            None       => Ok(value),
            Some(err)  => Err(FromError::from_error(err)),
        },
    }
}

#[test]
fn test_h5try() {
    use ffi::types::herr_t;
    use ffi::h5p::{H5Pcreate, H5Pclose, H5P_CLS_ROOT_ID};

    silence_errors();

    fn f1() -> H5Result<herr_t> {
        let plist_id = h5try!(H5Pcreate(*H5P_CLS_ROOT_ID));
        h5try!(H5Pclose(plist_id));
        Ok(100)
    }

    let result1 = f1();
    assert!(result1.is_ok());
    assert_eq!(result1.ok().unwrap(), 100);

    fn f2() -> H5Result<herr_t> {
        let plist_id = h5try!(H5Pcreate(*H5P_CLS_ROOT_ID));
        h5try!(H5Pclose(plist_id));
        h5try!(H5Pclose(plist_id));
        Ok(100)
    }

    let result2 = f2();
    assert!(result2.is_err());
}

<|endoftext|>


<commit_before>//! Error types and conversion functions.

use std;
use std::error::Error;
use std::fmt;

use gfx;
use gfx_window_sdl;

use image;
use rodio::decoder::DecoderError;
use sdl2;
use app_dirs::AppDirsError;
use toml;
use zip;

/// An enum containing all kinds of game framework errors.
#[derive(Debug)]
pub enum GameError {
    FilesystemError(String),
    ConfigError(String),
    ResourceLoadError(String),
    ResourceNotFound(String, Vec<std::path::PathBuf>),
    RenderError(String),
    AudioError(String),
    WindowError(gfx_window_sdl::InitError),
    IOError(std::io::Error),
    FontError(String),
    VideoError(String),
    UnknownError(String),
}

impl fmt::Display for GameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GameError::ResourceNotFound(ref s, ref paths) => write!(
                f,
                "Resource not found: {}, searched in paths {:?}",
                s,
                paths
            ),
            GameError::ConfigError(ref s) => write!(f, "Config error: {}", s),
            GameError::ResourceLoadError(ref s) => write!(f, "Error loading resource: {}", s),
            _ => write!(f, "GameError {:?}", self),
        }
    }
}

impl Error for GameError {
    fn description(&self) -> &str {
        match *self {
            GameError::FilesystemError(_) => "Filesystem error",
            GameError::ConfigError(_) => "Config file error",
            GameError::ResourceLoadError(_) => "Resource load error",
            GameError::ResourceNotFound(_, _) => "Resource not found",
            GameError::RenderError(_) => "Render error",
            GameError::AudioError(_) => "Audio error",
            GameError::WindowError(_) => "Window error",
            GameError::IOError(_) => "IO error",
            GameError::FontError(_) => "Font error",
            GameError::VideoError(_) => "Video error",
            GameError::UnknownError(_) => "Unknown error",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GameError::FilesystemError(ref _s) => None,
            GameError::ConfigError(ref _s) => None,
            GameError::ResourceLoadError(ref _s) => None,
            GameError::ResourceNotFound(ref _s, _) => None,
            GameError::RenderError(ref _s) => None,
            GameError::AudioError(ref _s) => None,
            GameError::WindowError(ref _s) => None,
            GameError::IOError(ref _s) => None,
            GameError::FontError(ref _s) => None,
            GameError::VideoError(ref _s) => None,
            GameError::UnknownError(ref _s) => None,
        }
    }
}

/// A convenient result type consisting of a return type and a `GameError`
pub type GameResult<T> = Result<T, GameError>;

/// Emit a non-fatal warning message
/// Ideally we probably want some sort of real logging interface here...
// fn warn(err: GameError) -> GameResult<()> {
//     println!("WARNING: Encountered error: {:?}", err);
//     Ok(())
// }

impl From<String> for GameError {
    fn from(s: String) -> GameError {
        GameError::UnknownError(s)
    }
}

impl From<gfx_window_sdl::InitError> for GameError {
    fn from(s: gfx_window_sdl::InitError) -> GameError {
        GameError::WindowError(s)
    }
}

impl From<sdl2::IntegerOrSdlError> for GameError {
    fn from(e: sdl2::IntegerOrSdlError) -> GameError {
        match e {
            sdl2::IntegerOrSdlError::IntegerOverflows(s, i) => {
                let message = format!("Integer overflow: {}, str {}", i, s);
                GameError::UnknownError(message)
            }
            sdl2::IntegerOrSdlError::SdlError(s) => GameError::UnknownError(s),
        }
    }
}

impl From<sdl2::filesystem::PrefPathError> for GameError {
    fn from(e: sdl2::filesystem::PrefPathError) -> GameError {
        let msg = match e {
            sdl2::filesystem::PrefPathError::InvalidOrganizationName(e) => {
                format!("Invalid organization name, {}", e)
            }
            sdl2::filesystem::PrefPathError::InvalidApplicationName(e) => {
                format!("Invalid application name, {}", e)
            }
            sdl2::filesystem::PrefPathError::SdlError(e) => e,
        };
        GameError::ConfigError(msg)
    }
}

impl From<sdl2::render::TextureValueError> for GameError {
    fn from(e: sdl2::render::TextureValueError) -> GameError {
        let msg = e.description();
        GameError::ResourceLoadError(msg.to_owned())
    }
}

impl From<AppDirsError> for GameError {
    fn from(e: AppDirsError) -> GameError {
        let errmessage = format!("{}", e);
        GameError::FilesystemError(errmessage)
    }
}
impl From<std::io::Error> for GameError {
    fn from(e: std::io::Error) -> GameError {
        GameError::IOError(e)
    }
}

impl From<toml::de::Error> for GameError {
    fn from(e: toml::de::Error) -> GameError {
        let errstr = format!("TOML decode error: {}", e.description());

        GameError::ConfigError(errstr)
    }
}

impl From<toml::ser::Error> for GameError {
    fn from(e: toml::ser::Error) -> GameError {
        let errstr = format!("TOML error (possibly encoding?): {}", e.description());
        GameError::ConfigError(errstr)
    }
}

impl From<zip::result::ZipError> for GameError {
    fn from(e: zip::result::ZipError) -> GameError {
        let errstr = format!("Zip error: {}", e.description());
        GameError::ResourceLoadError(errstr)
    }
}

impl From<DecoderError> for GameError {
    fn from(e: DecoderError) -> GameError {
        let errstr = format!("Audio decoder error: {:?}", e);
        GameError::AudioError(errstr)
    }
}

impl From<image::ImageError> for GameError {
    fn from(e: image::ImageError) -> GameError {
        let errstr = format!("Image load error: {}", e.description());
        GameError::ResourceLoadError(errstr)
    }
}

impl From<gfx::PipelineStateError<std::string::String>> for GameError {
    fn from(e: gfx::PipelineStateError<std::string::String>) -> GameError {
        let errstr = format!(
            "Error constructing pipeline!\nThis should probably not be \
             happening; it probably means an error in a shader or \
             something.\nError was: {:?}",
            e
        );
        GameError::VideoError(errstr)
    }
}

impl From<gfx::CombinedError> for GameError {
    fn from(e: gfx::CombinedError) -> GameError {
        let errstr = format!("Texture+view load error: {}", e.description());
        GameError::VideoError(errstr)
    }
}

impl<T> From<gfx::UpdateError<T>> for GameError
where
    T: fmt::Debug + fmt::Display + 'static,
{
    fn from(e: gfx::UpdateError<T>) -> GameError {
        let errstr = format!("Buffer update error: {}", e);
        GameError::VideoError(errstr)
    }
}
<commit_msg>Noodling around with better error handling, more.<commit_after>//! Error types and conversion functions.

use std;
use std::error::Error;
use std::fmt;

use gfx;
use gfx_window_sdl;

use image;
use rodio::decoder::DecoderError;
use sdl2;
use app_dirs::AppDirsError;
use toml;
use zip;

/// An enum containing all kinds of game framework errors.
#[derive(Debug)]
pub enum GameError {
    FilesystemError(String),
    ConfigError(String),
    ResourceLoadError(String),
    ResourceNotFound(String, Vec<std::path::PathBuf>),
    RenderError(String),
    AudioError(String),
    WindowError(gfx_window_sdl::InitError),
    IOError(std::io::Error),
    FontError(String),
    VideoError(String),
    UnknownError(String),
}

impl fmt::Display for GameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GameError::ResourceNotFound(ref s, ref paths) => write!(
                f,
                "Resource not found: {}, searched in paths {:?}",
                s,
                paths
            ),
            GameError::ConfigError(ref s) => write!(f, "Config error: {}", s),
            GameError::ResourceLoadError(ref s) => write!(f, "Error loading resource: {}", s),
            _ => write!(f, "GameError {:?}", self),
        }
    }
}

impl Error for GameError {
    fn description(&self) -> &str {
        match *self {
            GameError::FilesystemError(_) => "Filesystem error",
            GameError::ConfigError(_) => "Config file error",
            GameError::ResourceLoadError(_) => "Resource load error",
            GameError::ResourceNotFound(_, _) => "Resource not found",
            GameError::RenderError(_) => "Render error",
            GameError::AudioError(_) => "Audio error",
            GameError::WindowError(_) => "Window error",
            GameError::IOError(_) => "IO error",
            GameError::FontError(_) => "Font error",
            GameError::VideoError(_) => "Video error",
            GameError::UnknownError(_) => "Unknown error",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GameError::FilesystemError(ref _s) => None,
            GameError::ConfigError(ref _s) => None,
            GameError::ResourceLoadError(ref _s) => None,
            GameError::ResourceNotFound(ref _s, _) => None,
            GameError::RenderError(ref _s) => None,
            GameError::AudioError(ref _s) => None,
            GameError::WindowError(ref _we) => None,
            GameError::IOError(ref e) => Some(e),
            GameError::FontError(ref _s) => None,
            GameError::VideoError(ref _s) => None,
            GameError::UnknownError(ref _s) => None,
        }
    }
}

/// A convenient result type consisting of a return type and a `GameError`
pub type GameResult<T> = Result<T, GameError>;

impl From<String> for GameError {
    fn from(s: String) -> GameError {
        GameError::UnknownError(s)
    }
}

impl From<gfx_window_sdl::InitError> for GameError {
    fn from(s: gfx_window_sdl::InitError) -> GameError {
        GameError::WindowError(s)
    }
}

impl From<sdl2::IntegerOrSdlError> for GameError {
    fn from(e: sdl2::IntegerOrSdlError) -> GameError {
        match e {
            sdl2::IntegerOrSdlError::IntegerOverflows(s, i) => {
                let message = format!("Integer overflow: {}, str {}", i, s);
                GameError::UnknownError(message)
            }
            sdl2::IntegerOrSdlError::SdlError(s) => GameError::UnknownError(s),
        }
    }
}

impl From<sdl2::filesystem::PrefPathError> for GameError {
    fn from(e: sdl2::filesystem::PrefPathError) -> GameError {
        let msg = match e {
            sdl2::filesystem::PrefPathError::InvalidOrganizationName(e) => {
                format!("Invalid organization name, {}", e)
            }
            sdl2::filesystem::PrefPathError::InvalidApplicationName(e) => {
                format!("Invalid application name, {}", e)
            }
            sdl2::filesystem::PrefPathError::SdlError(e) => e,
        };
        GameError::ConfigError(msg)
    }
}

impl From<sdl2::render::TextureValueError> for GameError {
    fn from(e: sdl2::render::TextureValueError) -> GameError {
        let msg = e.description();
        GameError::ResourceLoadError(msg.to_owned())
    }
}

impl From<AppDirsError> for GameError {
    fn from(e: AppDirsError) -> GameError {
        let errmessage = format!("{}", e);
        GameError::FilesystemError(errmessage)
    }
}
impl From<std::io::Error> for GameError {
    fn from(e: std::io::Error) -> GameError {
        GameError::IOError(e)
    }
}

impl From<toml::de::Error> for GameError {
    fn from(e: toml::de::Error) -> GameError {
        let errstr = format!("TOML decode error: {}", e.description());

        GameError::ConfigError(errstr)
    }
}

impl From<toml::ser::Error> for GameError {
    fn from(e: toml::ser::Error) -> GameError {
        let errstr = format!("TOML error (possibly encoding?): {}", e.description());
        GameError::ConfigError(errstr)
    }
}

impl From<zip::result::ZipError> for GameError {
    fn from(e: zip::result::ZipError) -> GameError {
        let errstr = format!("Zip error: {}", e.description());
        GameError::ResourceLoadError(errstr)
    }
}

impl From<DecoderError> for GameError {
    fn from(e: DecoderError) -> GameError {
        let errstr = format!("Audio decoder error: {:?}", e);
        GameError::AudioError(errstr)
    }
}

impl From<image::ImageError> for GameError {
    fn from(e: image::ImageError) -> GameError {
        let errstr = format!("Image load error: {}", e.description());
        GameError::ResourceLoadError(errstr)
    }
}

impl From<gfx::PipelineStateError<std::string::String>> for GameError {
    fn from(e: gfx::PipelineStateError<std::string::String>) -> GameError {
        let errstr = format!(
            "Error constructing pipeline!\nThis should probably not be \
             happening; it probably means an error in a shader or \
             something.\nError was: {:?}",
            e
        );
        GameError::VideoError(errstr)
    }
}

impl From<gfx::CombinedError> for GameError {
    fn from(e: gfx::CombinedError) -> GameError {
        let errstr = format!("Texture+view load error: {}", e.description());
        GameError::VideoError(errstr)
    }
}

impl<T> From<gfx::UpdateError<T>> for GameError
where
    T: fmt::Debug + fmt::Display + 'static,
{
    fn from(e: gfx::UpdateError<T>) -> GameError {
        let errstr = format!("Buffer update error: {}", e);
        GameError::VideoError(errstr)
    }
}
<|endoftext|>