<commit_before>//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
//! itself is exposed at the crate root.

use crate::extern_type::ExternType;
use crate::kind::Trivial;
use crate::string::CxxString;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::iter::FusedIterator;
use core::marker::{PhantomData, PhantomPinned};
use core::mem;
use core::pin::Pin;
use core::ptr;
use core::slice;

#[doc(inline)]
pub use crate::Vector;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl<T> CxxVector<T>
where
    T: VectorElement,
{
    /// Returns the number of elements in the vector.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked(pos) })
        } else {
            None
        }
    }

    /// Returns a pinned mutable reference to an element at the given position,
    /// or `None` if out of bounds.
    pub fn get_mut(&mut self, pos: usize) -> Option<Pin<&mut T>> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked_mut(pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\] const][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        let this = self as *const CxxVector<T> as *mut CxxVector<T>;
        let ptr = T::__get_unchecked(this, pos) as *const T;
        &*ptr
    }

    /// Returns a pinned mutable reference to an element without doing bounds
    /// checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\]][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked_mut(&mut self, pos: usize) -> Pin<&mut T> {
        let ptr = T::__get_unchecked(self, pos);
        Pin::new_unchecked(&mut *ptr)
    }

    /// Returns a slice to the underlying contiguous array of elements.
    pub fn as_slice(&self) -> &[T]
    where
        T: ExternType<Kind = Trivial>,
    {
        let len = self.len();
        if len == 0 {
            // The slice::from_raw_parts in the other branch requires a nonnull
            // and properly aligned data ptr. C++ standard does not guarantee
            // that data() on a vector with size 0 would return a nonnull
            // pointer or sufficiently aligned pointer, so using it would be
            // undefined behavior. Create our own empty slice in Rust instead
            // which upholds the invariants.
            &[]
        } else {
            let this = self as *const CxxVector<T> as *mut CxxVector<T>;
            let ptr = unsafe { T::__get_unchecked(this, 0) };
            unsafe { slice::from_raw_parts(ptr, len) }
        }
    }

    /// Returns an iterator over elements of type `&T`.
    pub fn iter(&self) -> Iter<T> {
        Iter { v: self, index: 0 }
    }
}

/// Iterator over elements of a `CxxVector` by shared reference.
///
/// The iterator element type is `&'a T`.
pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T> IntoIterator for &'a CxxVector<T>
where
    T: VectorElement,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, T> Iterator for Iter<'a, T>
where
    T: VectorElement,
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.get(self.index)?;
        self.index += 1;
        Some(next)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<'a, T> FusedIterator for Iter<'a, T> where T: VectorElement {}

impl<T> Debug for CxxVector<T>
where
    T: VectorElement + Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_list().entries(self).finish()
    }
}

pub(crate) struct TypeName<T> {
    element: PhantomData<T>,
}

impl<T> TypeName<T> {
    pub const fn new() -> Self {
        TypeName {
            element: PhantomData,
        }
    }
}

impl<T> Display for TypeName<T>
where
    T: VectorElement,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "CxxVector<{}>", T::__NAME)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    const __NAME: &'static dyn Display;
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
    fn __unique_ptr_null() -> *mut c_void;
    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void;
    unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
    unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
    unsafe fn __unique_ptr_drop(repr: *mut c_void);
}

macro_rules! impl_vector_element {
    ($segment:expr, $name:expr, $ty:ty) => {
        const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());

        unsafe impl VectorElement for $ty {
            const __NAME: &'static dyn Display = &$name;
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: *mut CxxVector<$ty>, pos: usize) -> *mut $ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
                        fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
                    }
                }
                __get_unchecked(v, pos)
            }
            fn __unique_ptr_null() -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
                        fn __unique_ptr_null(this: *mut *mut c_void);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                unsafe { __unique_ptr_null(&mut repr) }
                repr
            }
            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
                        fn __unique_ptr_raw(this: *mut *mut c_void, raw: *mut CxxVector<$ty>);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                __unique_ptr_raw(&mut repr, raw);
                repr
            }
            unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
                        fn __unique_ptr_get(this: *const *mut c_void) -> *const CxxVector<$ty>;
                    }
                }
                __unique_ptr_get(&repr)
            }
            unsafe fn __unique_ptr_release(mut repr: *mut c_void) -> *mut CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
                        fn __unique_ptr_release(this: *mut *mut c_void) -> *mut CxxVector<$ty>;
                    }
                }
                __unique_ptr_release(&mut repr)
            }
            unsafe fn __unique_ptr_drop(mut repr: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
                        fn __unique_ptr_drop(this: *mut *mut c_void);
                    }
                }
                __unique_ptr_drop(&mut repr);
            }
        }
    };
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        impl_vector_element!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

impl_vector_element!("string", "CxxString", CxxString);
<commit_msg>Mutable iterator for CxxVector<commit_after>//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
//! itself is exposed at the crate root.

use crate::extern_type::ExternType;
use crate::kind::Trivial;
use crate::string::CxxString;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::iter::FusedIterator;
use core::marker::{PhantomData, PhantomPinned};
use core::mem;
use core::pin::Pin;
use core::ptr;
use core::slice;

#[doc(inline)]
pub use crate::Vector;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl<T> CxxVector<T>
where
    T: VectorElement,
{
    /// Returns the number of elements in the vector.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked(pos) })
        } else {
            None
        }
    }

    /// Returns a pinned mutable reference to an element at the given position,
    /// or `None` if out of bounds.
    pub fn get_mut(&mut self, pos: usize) -> Option<Pin<&mut T>> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked_mut(pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\] const][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        let this = self as *const CxxVector<T> as *mut CxxVector<T>;
        let ptr = T::__get_unchecked(this, pos) as *const T;
        &*ptr
    }

    /// Returns a pinned mutable reference to an element without doing bounds
    /// checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\]][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked_mut(&mut self, pos: usize) -> Pin<&mut T> {
        let ptr = T::__get_unchecked(self, pos);
        Pin::new_unchecked(&mut *ptr)
    }

    /// Returns a slice to the underlying contiguous array of elements.
    pub fn as_slice(&self) -> &[T]
    where
        T: ExternType<Kind = Trivial>,
    {
        let len = self.len();
        if len == 0 {
            // The slice::from_raw_parts in the other branch requires a nonnull
            // and properly aligned data ptr. C++ standard does not guarantee
            // that data() on a vector with size 0 would return a nonnull
            // pointer or sufficiently aligned pointer, so using it would be
            // undefined behavior. Create our own empty slice in Rust instead
            // which upholds the invariants.
            &[]
        } else {
            let this = self as *const CxxVector<T> as *mut CxxVector<T>;
            let ptr = unsafe { T::__get_unchecked(this, 0) };
            unsafe { slice::from_raw_parts(ptr, len) }
        }
    }

    /// Returns an iterator over elements of type `&T`.
    pub fn iter(&self) -> Iter<T> {
        Iter { v: self, index: 0 }
    }

    /// Returns an iterator over elements of type `Pin<&mut T>`.
    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { v: self, index: 0 }
    }
}

/// Iterator over elements of a `CxxVector` by shared reference.
///
/// The iterator element type is `&'a T`.
pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T> IntoIterator for &'a CxxVector<T>
where
    T: VectorElement,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, T> Iterator for Iter<'a, T>
where
    T: VectorElement,
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.get(self.index)?;
        self.index += 1;
        Some(next)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<'a, T> FusedIterator for Iter<'a, T> where T: VectorElement {}

/// Iterator over elements of a `CxxVector` by pinned mutable reference.
///
/// The iterator element type is `Pin<&'a mut T>`.
pub struct IterMut<'a, T> {
    v: &'a mut CxxVector<T>,
    index: usize,
}

impl<'a, T> IntoIterator for &'a mut CxxVector<T>
where
    T: VectorElement,
{
    type Item = Pin<&'a mut T>;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

impl<'a, T> Iterator for IterMut<'a, T>
where
    T: VectorElement,
{
    type Item = Pin<&'a mut T>;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.get_mut(self.index)?;
        self.index += 1;
        // Extend lifetime to allow simultaneous holding of nonoverlapping
        // elements, analogous to slice::split_first_mut.
        unsafe {
            let ptr = Pin::into_inner_unchecked(next) as *mut T;
            Some(Pin::new_unchecked(&mut *ptr))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for IterMut<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<'a, T> FusedIterator for IterMut<'a, T> where T: VectorElement {}

impl<T> Debug for CxxVector<T>
where
    T: VectorElement + Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_list().entries(self).finish()
    }
}

pub(crate) struct TypeName<T> {
    element: PhantomData<T>,
}

impl<T> TypeName<T> {
    pub const fn new() -> Self {
        TypeName {
            element: PhantomData,
        }
    }
}

impl<T> Display for TypeName<T>
where
    T: VectorElement,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "CxxVector<{}>", T::__NAME)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    const __NAME: &'static dyn Display;
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
    fn __unique_ptr_null() -> *mut c_void;
    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void;
    unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
    unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
    unsafe fn __unique_ptr_drop(repr: *mut c_void);
}

macro_rules! impl_vector_element {
    ($segment:expr, $name:expr, $ty:ty) => {
        const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());

        unsafe impl VectorElement for $ty {
            const __NAME: &'static dyn Display = &$name;
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: *mut CxxVector<$ty>, pos: usize) -> *mut $ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
                        fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
                    }
                }
                __get_unchecked(v, pos)
            }
            fn __unique_ptr_null() -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
                        fn __unique_ptr_null(this: *mut *mut c_void);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                unsafe { __unique_ptr_null(&mut repr) }
                repr
            }
            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
                        fn __unique_ptr_raw(this: *mut *mut c_void, raw: *mut CxxVector<$ty>);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                __unique_ptr_raw(&mut repr, raw);
                repr
            }
            unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
                        fn __unique_ptr_get(this: *const *mut c_void) -> *const CxxVector<$ty>;
                    }
                }
                __unique_ptr_get(&repr)
            }
            unsafe fn __unique_ptr_release(mut repr: *mut c_void) -> *mut CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
                        fn __unique_ptr_release(this: *mut *mut c_void) -> *mut CxxVector<$ty>;
                    }
                }
                __unique_ptr_release(&mut repr)
            }
            unsafe fn __unique_ptr_drop(mut repr: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
                        fn __unique_ptr_drop(this: *mut *mut c_void);
                    }
                }
                __unique_ptr_drop(&mut repr);
            }
        }
    };
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        impl_vector_element!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

impl_vector_element!("string", "CxxString", CxxString);
<|endoftext|>


<commit_before>use std::num::FromPrimitive;

use ffi;

pub type FtResult<T> = Result<T, Error>;

#[derive(Copy, Clone, PartialEq, Eq, Show)]
#[repr(i32)]
pub enum Error {
    Ok                          = ffi::FT_Err_Ok,
    CannotOpenResource          = ffi::FT_Err_Cannot_Open_Resource,
    UnknownFileFormat           = ffi::FT_Err_Unknown_File_Format,
    InvalidFileFormat           = ffi::FT_Err_Invalid_File_Format,
    InvalidVersion              = ffi::FT_Err_Invalid_Version,
    LowerModuleVersion          = ffi::FT_Err_Lower_Module_Version,
    InvalidArgument             = ffi::FT_Err_Invalid_Argument,
    UnimplementedFeature        = ffi::FT_Err_Unimplemented_Feature,
    InvalidTable                = ffi::FT_Err_Invalid_Table,
    InvalidOffset               = ffi::FT_Err_Invalid_Offset,
    ArrayTooLarge               = ffi::FT_Err_Array_Too_Large,
    MissingModule               = ffi::FT_Err_Missing_Module,
    MissingProperty             = ffi::FT_Err_Missing_Property,
    InvalidGlyphIndex           = ffi::FT_Err_Invalid_Glyph_Index,
    InvalidCharacterCode        = ffi::FT_Err_Invalid_Character_Code,
    InvalidGlyphFormat          = ffi::FT_Err_Invalid_Glyph_Format,
    CannotRenderGlyph           = ffi::FT_Err_Cannot_Render_Glyph,
    InvalidOutline              = ffi::FT_Err_Invalid_Outline,
    InvalidComposite            = ffi::FT_Err_Invalid_Composite,
    TooManyHints                = ffi::FT_Err_Too_Many_Hints,
    InvalidPixelSize            = ffi::FT_Err_Invalid_Pixel_Size,
    InvalidHandle               = ffi::FT_Err_Invalid_Handle,
    InvalidLibraryHandle        = ffi::FT_Err_Invalid_Library_Handle,
    InvalidDriverHandle         = ffi::FT_Err_Invalid_Driver_Handle,
    InvalidFaceHandle           = ffi::FT_Err_Invalid_Face_Handle,
    InvalidSizeHandle           = ffi::FT_Err_Invalid_Size_Handle,
    InvalidSlotHandle           = ffi::FT_Err_Invalid_Slot_Handle,
    InvalidCharMapHandle        = ffi::FT_Err_Invalid_CharMap_Handle,
    InvalidCacheHandle          = ffi::FT_Err_Invalid_Cache_Handle,
    InvalidStreamHandle         = ffi::FT_Err_Invalid_Stream_Handle,
    TooManyDrivers              = ffi::FT_Err_Too_Many_Drivers,
    TooManyExtensions           = ffi::FT_Err_Too_Many_Extensions,
    OutOfMemory                 = ffi::FT_Err_Out_Of_Memory,
    UnlistedObject              = ffi::FT_Err_Unlisted_Object,
    CannotOpenStream            = ffi::FT_Err_Cannot_Open_Stream,
    InvalidStreamSeek           = ffi::FT_Err_Invalid_Stream_Seek,
    InvalidStreamSkip           = ffi::FT_Err_Invalid_Stream_Skip,
    InvalidStreamRead           = ffi::FT_Err_Invalid_Stream_Read,
    InvalidStreamOperation      = ffi::FT_Err_Invalid_Stream_Operation,
    InvalidFrameOperation       = ffi::FT_Err_Invalid_Frame_Operation,
    NestedFrameAccess           = ffi::FT_Err_Nested_Frame_Access,
    InvalidFrameRead            = ffi::FT_Err_Invalid_Frame_Read,
    RasterUninitialized         = ffi::FT_Err_Raster_Uninitialized,
    RasterCorrupted             = ffi::FT_Err_Raster_Corrupted,
    RasterOverflow              = ffi::FT_Err_Raster_Overflow,
    RasterNegativeHeight        = ffi::FT_Err_Raster_Negative_Height,
    TooManyCaches               = ffi::FT_Err_Too_Many_Caches,
    InvalidOpcode               = ffi::FT_Err_Invalid_Opcode,
    TooFewArguments             = ffi::FT_Err_Too_Few_Arguments,
    StackOverflow               = ffi::FT_Err_Stack_Overflow,
    CodeOverflow                = ffi::FT_Err_Code_Overflow,
    BadArgument                 = ffi::FT_Err_Bad_Argument,
    DivideByZero                = ffi::FT_Err_Divide_By_Zero,
    InvalidReference            = ffi::FT_Err_Invalid_Reference,
    DebugOpCode                 = ffi::FT_Err_Debug_OpCode,
    ENDFInExecStream            = ffi::FT_Err_ENDF_In_Exec_Stream,
    NestedDEFS                  = ffi::FT_Err_Nested_DEFS,
    InvalidCodeRange            = ffi::FT_Err_Invalid_CodeRange,
    ExecutionTooLong            = ffi::FT_Err_Execution_Too_Long,
    TooManyFunctionDefs         = ffi::FT_Err_Too_Many_Function_Defs,
    TooManyInstructionDefs      = ffi::FT_Err_Too_Many_Instruction_Defs,
    TableMissing                = ffi::FT_Err_Table_Missing,
    HorizHeaderMissing          = ffi::FT_Err_Horiz_Header_Missing,
    LocationsMissing            = ffi::FT_Err_Locations_Missing,
    NameTableMissing            = ffi::FT_Err_Name_Table_Missing,
    CMapTableMissing            = ffi::FT_Err_CMap_Table_Missing,
    HmtxTableMissing            = ffi::FT_Err_Hmtx_Table_Missing,
    PostTableMissing            = ffi::FT_Err_Post_Table_Missing,
    InvalidHorizMetrics         = ffi::FT_Err_Invalid_Horiz_Metrics,
    InvalidCharMapFormat        = ffi::FT_Err_Invalid_CharMap_Format,
    InvalidPPem                 = ffi::FT_Err_Invalid_PPem,
    InvalidVertMetrics          = ffi::FT_Err_Invalid_Vert_Metrics,
    CouldNotFindContext         = ffi::FT_Err_Could_Not_Find_Context,
    InvalidPostTableFormat      = ffi::FT_Err_Invalid_Post_Table_Format,
    InvalidPostTable            = ffi::FT_Err_Invalid_Post_Table,
    SyntaxError                 = ffi::FT_Err_Syntax_Error,
    StackUnderflow              = ffi::FT_Err_Stack_Underflow,
    Ignore                      = ffi::FT_Err_Ignore,
    NoUnicodeGlyphName          = ffi::FT_Err_No_Unicode_Glyph_Name,
    MissingStartfontField       = ffi::FT_Err_Missing_Startfont_Field,
    MissingFontField            = ffi::FT_Err_Missing_Font_Field,
    MissingSizeField            = ffi::FT_Err_Missing_Size_Field,
    MissingFontboundingboxField = ffi::FT_Err_Missing_Fontboundingbox_Field,
    MissingCharsField           = ffi::FT_Err_Missing_Chars_Field,
    MissingStartcharField       = ffi::FT_Err_Missing_Startchar_Field,
    MissingEncodingField        = ffi::FT_Err_Missing_Encoding_Field,
    MissingBbxField             = ffi::FT_Err_Missing_Bbx_Field,
    BbxTooBig                   = ffi::FT_Err_Bbx_Too_Big,
    CorruptedFontHeader         = ffi::FT_Err_Corrupted_Font_Header,
    CorruptedFontGlyphs         = ffi::FT_Err_Corrupted_Font_Glyphs,
    Max                         = ffi::FT_Err_Max,
    UnknownError,
}

impl FromPrimitive for Error {
    fn from_i64(n: i64) -> Option<Error> {
        FromPrimitive::from_i32(n as i32)
    }

    fn from_u64(n: u64) -> Option<Error> {
        FromPrimitive::from_i32(n as i32)
    }

    #[allow(non_upper_case_globals)]
    fn from_i32(n: i32) -> Option<Error> {
        match n {
            ffi::FT_Err_Ok                            => Some(Error::Ok),
            ffi::FT_Err_Cannot_Open_Resource          => Some(Error::CannotOpenResource),
            ffi::FT_Err_Unknown_File_Format           => Some(Error::UnknownFileFormat),
            ffi::FT_Err_Invalid_File_Format           => Some(Error::InvalidFileFormat),
            ffi::FT_Err_Invalid_Version               => Some(Error::InvalidVersion),
            ffi::FT_Err_Lower_Module_Version          => Some(Error::LowerModuleVersion),
            ffi::FT_Err_Invalid_Argument              => Some(Error::InvalidArgument),
            ffi::FT_Err_Unimplemented_Feature         => Some(Error::UnimplementedFeature),
            ffi::FT_Err_Invalid_Table                 => Some(Error::InvalidTable),
            ffi::FT_Err_Invalid_Offset                => Some(Error::InvalidOffset),
            ffi::FT_Err_Array_Too_Large               => Some(Error::ArrayTooLarge),
            ffi::FT_Err_Missing_Module                => Some(Error::MissingModule),
            ffi::FT_Err_Missing_Property              => Some(Error::MissingProperty),
            ffi::FT_Err_Invalid_Glyph_Index           => Some(Error::InvalidGlyphIndex),
            ffi::FT_Err_Invalid_Character_Code        => Some(Error::InvalidCharacterCode),
            ffi::FT_Err_Invalid_Glyph_Format          => Some(Error::InvalidGlyphFormat),
            ffi::FT_Err_Cannot_Render_Glyph           => Some(Error::CannotRenderGlyph),
            ffi::FT_Err_Invalid_Outline               => Some(Error::InvalidOutline),
            ffi::FT_Err_Invalid_Composite             => Some(Error::InvalidComposite),
            ffi::FT_Err_Too_Many_Hints                => Some(Error::TooManyHints),
            ffi::FT_Err_Invalid_Pixel_Size            => Some(Error::InvalidPixelSize),
            ffi::FT_Err_Invalid_Handle                => Some(Error::InvalidHandle),
            ffi::FT_Err_Invalid_Library_Handle        => Some(Error::InvalidLibraryHandle),
            ffi::FT_Err_Invalid_Driver_Handle         => Some(Error::InvalidDriverHandle),
            ffi::FT_Err_Invalid_Face_Handle           => Some(Error::InvalidFaceHandle),
            ffi::FT_Err_Invalid_Size_Handle           => Some(Error::InvalidSizeHandle),
            ffi::FT_Err_Invalid_Slot_Handle           => Some(Error::InvalidSlotHandle),
            ffi::FT_Err_Invalid_CharMap_Handle        => Some(Error::InvalidCharMapHandle),
            ffi::FT_Err_Invalid_Cache_Handle          => Some(Error::InvalidCacheHandle),
            ffi::FT_Err_Invalid_Stream_Handle         => Some(Error::InvalidStreamHandle),
            ffi::FT_Err_Too_Many_Drivers              => Some(Error::TooManyDrivers),
            ffi::FT_Err_Too_Many_Extensions           => Some(Error::TooManyExtensions),
            ffi::FT_Err_Out_Of_Memory                 => Some(Error::OutOfMemory),
            ffi::FT_Err_Unlisted_Object               => Some(Error::UnlistedObject),
            ffi::FT_Err_Cannot_Open_Stream            => Some(Error::CannotOpenStream),
            ffi::FT_Err_Invalid_Stream_Seek           => Some(Error::InvalidStreamSeek),
            ffi::FT_Err_Invalid_Stream_Skip           => Some(Error::InvalidStreamSkip),
            ffi::FT_Err_Invalid_Stream_Read           => Some(Error::InvalidStreamRead),
            ffi::FT_Err_Invalid_Stream_Operation      => Some(Error::InvalidStreamOperation),
            ffi::FT_Err_Invalid_Frame_Operation       => Some(Error::InvalidFrameOperation),
            ffi::FT_Err_Nested_Frame_Access           => Some(Error::NestedFrameAccess),
            ffi::FT_Err_Invalid_Frame_Read            => Some(Error::InvalidFrameRead),
            ffi::FT_Err_Raster_Uninitialized          => Some(Error::RasterUninitialized),
            ffi::FT_Err_Raster_Corrupted              => Some(Error::RasterCorrupted),
            ffi::FT_Err_Raster_Overflow               => Some(Error::RasterOverflow),
            ffi::FT_Err_Raster_Negative_Height        => Some(Error::RasterNegativeHeight),
            ffi::FT_Err_Too_Many_Caches               => Some(Error::TooManyCaches),
            ffi::FT_Err_Invalid_Opcode                => Some(Error::InvalidOpcode),
            ffi::FT_Err_Too_Few_Arguments             => Some(Error::TooFewArguments),
            ffi::FT_Err_Stack_Overflow                => Some(Error::StackOverflow),
            ffi::FT_Err_Code_Overflow                 => Some(Error::CodeOverflow),
            ffi::FT_Err_Bad_Argument                  => Some(Error::BadArgument),
            ffi::FT_Err_Divide_By_Zero                => Some(Error::DivideByZero),
            ffi::FT_Err_Invalid_Reference             => Some(Error::InvalidReference),
            ffi::FT_Err_Debug_OpCode                  => Some(Error::DebugOpCode),
            ffi::FT_Err_ENDF_In_Exec_Stream           => Some(Error::ENDFInExecStream),
            ffi::FT_Err_Nested_DEFS                   => Some(Error::NestedDEFS),
            ffi::FT_Err_Invalid_CodeRange             => Some(Error::InvalidCodeRange),
            ffi::FT_Err_Execution_Too_Long            => Some(Error::ExecutionTooLong),
            ffi::FT_Err_Too_Many_Function_Defs        => Some(Error::TooManyFunctionDefs),
            ffi::FT_Err_Too_Many_Instruction_Defs     => Some(Error::TooManyInstructionDefs),
            ffi::FT_Err_Table_Missing                 => Some(Error::TableMissing),
            ffi::FT_Err_Horiz_Header_Missing          => Some(Error::HorizHeaderMissing),
            ffi::FT_Err_Locations_Missing             => Some(Error::LocationsMissing),
            ffi::FT_Err_Name_Table_Missing            => Some(Error::NameTableMissing),
            ffi::FT_Err_CMap_Table_Missing            => Some(Error::CMapTableMissing),
            ffi::FT_Err_Hmtx_Table_Missing            => Some(Error::HmtxTableMissing),
            ffi::FT_Err_Post_Table_Missing            => Some(Error::PostTableMissing),
            ffi::FT_Err_Invalid_Horiz_Metrics         => Some(Error::InvalidHorizMetrics),
            ffi::FT_Err_Invalid_CharMap_Format        => Some(Error::InvalidCharMapFormat),
            ffi::FT_Err_Invalid_PPem                  => Some(Error::InvalidPPem),
            ffi::FT_Err_Invalid_Vert_Metrics          => Some(Error::InvalidVertMetrics),
            ffi::FT_Err_Could_Not_Find_Context        => Some(Error::CouldNotFindContext),
            ffi::FT_Err_Invalid_Post_Table_Format     => Some(Error::InvalidPostTableFormat),
            ffi::FT_Err_Invalid_Post_Table            => Some(Error::InvalidPostTable),
            ffi::FT_Err_Syntax_Error                  => Some(Error::SyntaxError),
            ffi::FT_Err_Stack_Underflow               => Some(Error::StackUnderflow),
            ffi::FT_Err_Ignore                        => Some(Error::Ignore),
            ffi::FT_Err_No_Unicode_Glyph_Name         => Some(Error::NoUnicodeGlyphName),
            ffi::FT_Err_Missing_Startfont_Field       => Some(Error::MissingStartfontField),
            ffi::FT_Err_Missing_Font_Field            => Some(Error::MissingFontField),
            ffi::FT_Err_Missing_Size_Field            => Some(Error::MissingSizeField),
            ffi::FT_Err_Missing_Fontboundingbox_Field => Some(Error::MissingFontboundingboxField),
            ffi::FT_Err_Missing_Chars_Field           => Some(Error::MissingCharsField),
            ffi::FT_Err_Missing_Startchar_Field       => Some(Error::MissingStartcharField),
            ffi::FT_Err_Missing_Encoding_Field        => Some(Error::MissingEncodingField),
            ffi::FT_Err_Missing_Bbx_Field             => Some(Error::MissingBbxField),
            ffi::FT_Err_Bbx_Too_Big                   => Some(Error::BbxTooBig),
            ffi::FT_Err_Corrupted_Font_Header         => Some(Error::CorruptedFontHeader),
            ffi::FT_Err_Corrupted_Font_Glyphs         => Some(Error::CorruptedFontGlyphs),
            ffi::FT_Err_Max                           => Some(Error::Max),
            _ => Some(Error::UnknownError),
        }
    }
}

<commit_msg>Upgraded to latest Rust<commit_after>use std::num::FromPrimitive;
use std::fmt;

use ffi;

pub type FtResult<T> = Result<T, Error>;

#[derive(Copy, Clone, PartialEq, Eq, Show)]
#[repr(i32)]
pub enum Error {
    Ok                          = ffi::FT_Err_Ok,
    CannotOpenResource          = ffi::FT_Err_Cannot_Open_Resource,
    UnknownFileFormat           = ffi::FT_Err_Unknown_File_Format,
    InvalidFileFormat           = ffi::FT_Err_Invalid_File_Format,
    InvalidVersion              = ffi::FT_Err_Invalid_Version,
    LowerModuleVersion          = ffi::FT_Err_Lower_Module_Version,
    InvalidArgument             = ffi::FT_Err_Invalid_Argument,
    UnimplementedFeature        = ffi::FT_Err_Unimplemented_Feature,
    InvalidTable                = ffi::FT_Err_Invalid_Table,
    InvalidOffset               = ffi::FT_Err_Invalid_Offset,
    ArrayTooLarge               = ffi::FT_Err_Array_Too_Large,
    MissingModule               = ffi::FT_Err_Missing_Module,
    MissingProperty             = ffi::FT_Err_Missing_Property,
    InvalidGlyphIndex           = ffi::FT_Err_Invalid_Glyph_Index,
    InvalidCharacterCode        = ffi::FT_Err_Invalid_Character_Code,
    InvalidGlyphFormat          = ffi::FT_Err_Invalid_Glyph_Format,
    CannotRenderGlyph           = ffi::FT_Err_Cannot_Render_Glyph,
    InvalidOutline              = ffi::FT_Err_Invalid_Outline,
    InvalidComposite            = ffi::FT_Err_Invalid_Composite,
    TooManyHints                = ffi::FT_Err_Too_Many_Hints,
    InvalidPixelSize            = ffi::FT_Err_Invalid_Pixel_Size,
    InvalidHandle               = ffi::FT_Err_Invalid_Handle,
    InvalidLibraryHandle        = ffi::FT_Err_Invalid_Library_Handle,
    InvalidDriverHandle         = ffi::FT_Err_Invalid_Driver_Handle,
    InvalidFaceHandle           = ffi::FT_Err_Invalid_Face_Handle,
    InvalidSizeHandle           = ffi::FT_Err_Invalid_Size_Handle,
    InvalidSlotHandle           = ffi::FT_Err_Invalid_Slot_Handle,
    InvalidCharMapHandle        = ffi::FT_Err_Invalid_CharMap_Handle,
    InvalidCacheHandle          = ffi::FT_Err_Invalid_Cache_Handle,
    InvalidStreamHandle         = ffi::FT_Err_Invalid_Stream_Handle,
    TooManyDrivers              = ffi::FT_Err_Too_Many_Drivers,
    TooManyExtensions           = ffi::FT_Err_Too_Many_Extensions,
    OutOfMemory                 = ffi::FT_Err_Out_Of_Memory,
    UnlistedObject              = ffi::FT_Err_Unlisted_Object,
    CannotOpenStream            = ffi::FT_Err_Cannot_Open_Stream,
    InvalidStreamSeek           = ffi::FT_Err_Invalid_Stream_Seek,
    InvalidStreamSkip           = ffi::FT_Err_Invalid_Stream_Skip,
    InvalidStreamRead           = ffi::FT_Err_Invalid_Stream_Read,
    InvalidStreamOperation      = ffi::FT_Err_Invalid_Stream_Operation,
    InvalidFrameOperation       = ffi::FT_Err_Invalid_Frame_Operation,
    NestedFrameAccess           = ffi::FT_Err_Nested_Frame_Access,
    InvalidFrameRead            = ffi::FT_Err_Invalid_Frame_Read,
    RasterUninitialized         = ffi::FT_Err_Raster_Uninitialized,
    RasterCorrupted             = ffi::FT_Err_Raster_Corrupted,
    RasterOverflow              = ffi::FT_Err_Raster_Overflow,
    RasterNegativeHeight        = ffi::FT_Err_Raster_Negative_Height,
    TooManyCaches               = ffi::FT_Err_Too_Many_Caches,
    InvalidOpcode               = ffi::FT_Err_Invalid_Opcode,
    TooFewArguments             = ffi::FT_Err_Too_Few_Arguments,
    StackOverflow               = ffi::FT_Err_Stack_Overflow,
    CodeOverflow                = ffi::FT_Err_Code_Overflow,
    BadArgument                 = ffi::FT_Err_Bad_Argument,
    DivideByZero                = ffi::FT_Err_Divide_By_Zero,
    InvalidReference            = ffi::FT_Err_Invalid_Reference,
    DebugOpCode                 = ffi::FT_Err_Debug_OpCode,
    ENDFInExecStream            = ffi::FT_Err_ENDF_In_Exec_Stream,
    NestedDEFS                  = ffi::FT_Err_Nested_DEFS,
    InvalidCodeRange            = ffi::FT_Err_Invalid_CodeRange,
    ExecutionTooLong            = ffi::FT_Err_Execution_Too_Long,
    TooManyFunctionDefs         = ffi::FT_Err_Too_Many_Function_Defs,
    TooManyInstructionDefs      = ffi::FT_Err_Too_Many_Instruction_Defs,
    TableMissing                = ffi::FT_Err_Table_Missing,
    HorizHeaderMissing          = ffi::FT_Err_Horiz_Header_Missing,
    LocationsMissing            = ffi::FT_Err_Locations_Missing,
    NameTableMissing            = ffi::FT_Err_Name_Table_Missing,
    CMapTableMissing            = ffi::FT_Err_CMap_Table_Missing,
    HmtxTableMissing            = ffi::FT_Err_Hmtx_Table_Missing,
    PostTableMissing            = ffi::FT_Err_Post_Table_Missing,
    InvalidHorizMetrics         = ffi::FT_Err_Invalid_Horiz_Metrics,
    InvalidCharMapFormat        = ffi::FT_Err_Invalid_CharMap_Format,
    InvalidPPem                 = ffi::FT_Err_Invalid_PPem,
    InvalidVertMetrics          = ffi::FT_Err_Invalid_Vert_Metrics,
    CouldNotFindContext         = ffi::FT_Err_Could_Not_Find_Context,
    InvalidPostTableFormat      = ffi::FT_Err_Invalid_Post_Table_Format,
    InvalidPostTable            = ffi::FT_Err_Invalid_Post_Table,
    SyntaxError                 = ffi::FT_Err_Syntax_Error,
    StackUnderflow              = ffi::FT_Err_Stack_Underflow,
    Ignore                      = ffi::FT_Err_Ignore,
    NoUnicodeGlyphName          = ffi::FT_Err_No_Unicode_Glyph_Name,
    MissingStartfontField       = ffi::FT_Err_Missing_Startfont_Field,
    MissingFontField            = ffi::FT_Err_Missing_Font_Field,
    MissingSizeField            = ffi::FT_Err_Missing_Size_Field,
    MissingFontboundingboxField = ffi::FT_Err_Missing_Fontboundingbox_Field,
    MissingCharsField           = ffi::FT_Err_Missing_Chars_Field,
    MissingStartcharField       = ffi::FT_Err_Missing_Startchar_Field,
    MissingEncodingField        = ffi::FT_Err_Missing_Encoding_Field,
    MissingBbxField             = ffi::FT_Err_Missing_Bbx_Field,
    BbxTooBig                   = ffi::FT_Err_Bbx_Too_Big,
    CorruptedFontHeader         = ffi::FT_Err_Corrupted_Font_Header,
    CorruptedFontGlyphs         = ffi::FT_Err_Corrupted_Font_Glyphs,
    Max                         = ffi::FT_Err_Max,
    UnknownError,
}

impl FromPrimitive for Error {
    fn from_i64(n: i64) -> Option<Error> {
        FromPrimitive::from_i32(n as i32)
    }

    fn from_u64(n: u64) -> Option<Error> {
        FromPrimitive::from_i32(n as i32)
    }

    #[allow(non_upper_case_globals)]
    fn from_i32(n: i32) -> Option<Error> {
        match n {
            ffi::FT_Err_Ok                            => Some(Error::Ok),
            ffi::FT_Err_Cannot_Open_Resource          => Some(Error::CannotOpenResource),
            ffi::FT_Err_Unknown_File_Format           => Some(Error::UnknownFileFormat),
            ffi::FT_Err_Invalid_File_Format           => Some(Error::InvalidFileFormat),
            ffi::FT_Err_Invalid_Version               => Some(Error::InvalidVersion),
            ffi::FT_Err_Lower_Module_Version          => Some(Error::LowerModuleVersion),
            ffi::FT_Err_Invalid_Argument              => Some(Error::InvalidArgument),
            ffi::FT_Err_Unimplemented_Feature         => Some(Error::UnimplementedFeature),
            ffi::FT_Err_Invalid_Table                 => Some(Error::InvalidTable),
            ffi::FT_Err_Invalid_Offset                => Some(Error::InvalidOffset),
            ffi::FT_Err_Array_Too_Large               => Some(Error::ArrayTooLarge),
            ffi::FT_Err_Missing_Module                => Some(Error::MissingModule),
            ffi::FT_Err_Missing_Property              => Some(Error::MissingProperty),
            ffi::FT_Err_Invalid_Glyph_Index           => Some(Error::InvalidGlyphIndex),
            ffi::FT_Err_Invalid_Character_Code        => Some(Error::InvalidCharacterCode),
            ffi::FT_Err_Invalid_Glyph_Format          => Some(Error::InvalidGlyphFormat),
            ffi::FT_Err_Cannot_Render_Glyph           => Some(Error::CannotRenderGlyph),
            ffi::FT_Err_Invalid_Outline               => Some(Error::InvalidOutline),
            ffi::FT_Err_Invalid_Composite             => Some(Error::InvalidComposite),
            ffi::FT_Err_Too_Many_Hints                => Some(Error::TooManyHints),
            ffi::FT_Err_Invalid_Pixel_Size            => Some(Error::InvalidPixelSize),
            ffi::FT_Err_Invalid_Handle                => Some(Error::InvalidHandle),
            ffi::FT_Err_Invalid_Library_Handle        => Some(Error::InvalidLibraryHandle),
            ffi::FT_Err_Invalid_Driver_Handle         => Some(Error::InvalidDriverHandle),
            ffi::FT_Err_Invalid_Face_Handle           => Some(Error::InvalidFaceHandle),
            ffi::FT_Err_Invalid_Size_Handle           => Some(Error::InvalidSizeHandle),
            ffi::FT_Err_Invalid_Slot_Handle           => Some(Error::InvalidSlotHandle),
            ffi::FT_Err_Invalid_CharMap_Handle        => Some(Error::InvalidCharMapHandle),
            ffi::FT_Err_Invalid_Cache_Handle          => Some(Error::InvalidCacheHandle),
            ffi::FT_Err_Invalid_Stream_Handle         => Some(Error::InvalidStreamHandle),
            ffi::FT_Err_Too_Many_Drivers              => Some(Error::TooManyDrivers),
            ffi::FT_Err_Too_Many_Extensions           => Some(Error::TooManyExtensions),
            ffi::FT_Err_Out_Of_Memory                 => Some(Error::OutOfMemory),
            ffi::FT_Err_Unlisted_Object               => Some(Error::UnlistedObject),
            ffi::FT_Err_Cannot_Open_Stream            => Some(Error::CannotOpenStream),
            ffi::FT_Err_Invalid_Stream_Seek           => Some(Error::InvalidStreamSeek),
            ffi::FT_Err_Invalid_Stream_Skip           => Some(Error::InvalidStreamSkip),
            ffi::FT_Err_Invalid_Stream_Read           => Some(Error::InvalidStreamRead),
            ffi::FT_Err_Invalid_Stream_Operation      => Some(Error::InvalidStreamOperation),
            ffi::FT_Err_Invalid_Frame_Operation       => Some(Error::InvalidFrameOperation),
            ffi::FT_Err_Nested_Frame_Access           => Some(Error::NestedFrameAccess),
            ffi::FT_Err_Invalid_Frame_Read            => Some(Error::InvalidFrameRead),
            ffi::FT_Err_Raster_Uninitialized          => Some(Error::RasterUninitialized),
            ffi::FT_Err_Raster_Corrupted              => Some(Error::RasterCorrupted),
            ffi::FT_Err_Raster_Overflow               => Some(Error::RasterOverflow),
            ffi::FT_Err_Raster_Negative_Height        => Some(Error::RasterNegativeHeight),
            ffi::FT_Err_Too_Many_Caches               => Some(Error::TooManyCaches),
            ffi::FT_Err_Invalid_Opcode                => Some(Error::InvalidOpcode),
            ffi::FT_Err_Too_Few_Arguments             => Some(Error::TooFewArguments),
            ffi::FT_Err_Stack_Overflow                => Some(Error::StackOverflow),
            ffi::FT_Err_Code_Overflow                 => Some(Error::CodeOverflow),
            ffi::FT_Err_Bad_Argument                  => Some(Error::BadArgument),
            ffi::FT_Err_Divide_By_Zero                => Some(Error::DivideByZero),
            ffi::FT_Err_Invalid_Reference             => Some(Error::InvalidReference),
            ffi::FT_Err_Debug_OpCode                  => Some(Error::DebugOpCode),
            ffi::FT_Err_ENDF_In_Exec_Stream           => Some(Error::ENDFInExecStream),
            ffi::FT_Err_Nested_DEFS                   => Some(Error::NestedDEFS),
            ffi::FT_Err_Invalid_CodeRange             => Some(Error::InvalidCodeRange),
            ffi::FT_Err_Execution_Too_Long            => Some(Error::ExecutionTooLong),
            ffi::FT_Err_Too_Many_Function_Defs        => Some(Error::TooManyFunctionDefs),
            ffi::FT_Err_Too_Many_Instruction_Defs     => Some(Error::TooManyInstructionDefs),
            ffi::FT_Err_Table_Missing                 => Some(Error::TableMissing),
            ffi::FT_Err_Horiz_Header_Missing          => Some(Error::HorizHeaderMissing),
            ffi::FT_Err_Locations_Missing             => Some(Error::LocationsMissing),
            ffi::FT_Err_Name_Table_Missing            => Some(Error::NameTableMissing),
            ffi::FT_Err_CMap_Table_Missing            => Some(Error::CMapTableMissing),
            ffi::FT_Err_Hmtx_Table_Missing            => Some(Error::HmtxTableMissing),
            ffi::FT_Err_Post_Table_Missing            => Some(Error::PostTableMissing),
            ffi::FT_Err_Invalid_Horiz_Metrics         => Some(Error::InvalidHorizMetrics),
            ffi::FT_Err_Invalid_CharMap_Format        => Some(Error::InvalidCharMapFormat),
            ffi::FT_Err_Invalid_PPem                  => Some(Error::InvalidPPem),
            ffi::FT_Err_Invalid_Vert_Metrics          => Some(Error::InvalidVertMetrics),
            ffi::FT_Err_Could_Not_Find_Context        => Some(Error::CouldNotFindContext),
            ffi::FT_Err_Invalid_Post_Table_Format     => Some(Error::InvalidPostTableFormat),
            ffi::FT_Err_Invalid_Post_Table            => Some(Error::InvalidPostTable),
            ffi::FT_Err_Syntax_Error                  => Some(Error::SyntaxError),
            ffi::FT_Err_Stack_Underflow               => Some(Error::StackUnderflow),
            ffi::FT_Err_Ignore                        => Some(Error::Ignore),
            ffi::FT_Err_No_Unicode_Glyph_Name         => Some(Error::NoUnicodeGlyphName),
            ffi::FT_Err_Missing_Startfont_Field       => Some(Error::MissingStartfontField),
            ffi::FT_Err_Missing_Font_Field            => Some(Error::MissingFontField),
            ffi::FT_Err_Missing_Size_Field            => Some(Error::MissingSizeField),
            ffi::FT_Err_Missing_Fontboundingbox_Field => Some(Error::MissingFontboundingboxField),
            ffi::FT_Err_Missing_Chars_Field           => Some(Error::MissingCharsField),
            ffi::FT_Err_Missing_Startchar_Field       => Some(Error::MissingStartcharField),
            ffi::FT_Err_Missing_Encoding_Field        => Some(Error::MissingEncodingField),
            ffi::FT_Err_Missing_Bbx_Field             => Some(Error::MissingBbxField),
            ffi::FT_Err_Bbx_Too_Big                   => Some(Error::BbxTooBig),
            ffi::FT_Err_Corrupted_Font_Header         => Some(Error::CorruptedFontHeader),
            ffi::FT_Err_Corrupted_Font_Glyphs         => Some(Error::CorruptedFontGlyphs),
            ffi::FT_Err_Max                           => Some(Error::Max),
            _ => Some(Error::UnknownError),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Show;

        self.fmt(f)
    }
}
<|endoftext|>


<commit_before>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io;

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

type Cause = Box<dyn StdError + Send + Sync>;

/// Represents errors that can occur handling HTTP streams.
pub struct Error {
    inner: Box<ErrorImpl>,
}

struct ErrorImpl {
    kind: Kind,
    cause: Option<Cause>,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Kind {
    Parse(Parse),
    User(User),
    /// A message reached EOF, but is not complete.
    IncompleteMessage,
    /// A connection received a message (or bytes) when not waiting for one.
    UnexpectedMessage,
    /// A pending item was dropped before ever being processed.
    Canceled,
    /// Indicates a channel (client or body sender) is closed.
    ChannelClosed,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io,
    /// Error occurred while connecting.
    Connect,
    /// Error creating a TcpListener.
    #[cfg(feature = "tcp")]
    Listen,
    /// Error accepting on an Incoming stream.
    Accept,
    /// Error while reading a body from connection.
    Body,
    /// Error while writing a body to connection.
    BodyWrite,
    /// The body write was aborted.
    BodyWriteAborted,
    /// Error calling AsyncWrite::shutdown()
    Shutdown,

    /// A general error from h2.
    Http2,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Parse {
    Method,
    Version,
    VersionH2,
    Uri,
    Header,
    TooLarge,
    Status,
}

#[derive(Debug, PartialEq)]
pub(crate) enum User {
    /// Error calling user's Payload::poll_data().
    Body,
    /// Error calling user's MakeService.
    MakeService,
    /// Error from future of user's Service.
    Service,
    /// User tried to send a certain header in an unexpected context.
    ///
    /// For example, sending both `content-length` and `transfer-encoding`.
    UnexpectedHeader,
    /// User tried to create a Request with bad version.
    UnsupportedVersion,
    /// User tried to create a CONNECT Request with the Client.
    UnsupportedRequestMethod,
    /// User tried to respond with a 1xx (not 101) response code.
    UnsupportedStatusCode,
    /// User tried to send a Request with Client with non-absolute URI.
    AbsoluteUriRequired,

    /// User tried polling for an upgrade that doesn't exist.
    NoUpgrade,

    /// User polled for an upgrade, but low-level API is not using upgrades.
    ManualUpgrade,

    /// Error trying to call `Executor::execute`.
    Execute,
}

impl Error {
    /// Returns true if this was an HTTP parse error.
    pub fn is_parse(&self) -> bool {
        match self.inner.kind {
            Kind::Parse(_) => true,
            _ => false,
        }
    }

    /// Returns true if this error was caused by user code.
    pub fn is_user(&self) -> bool {
        match self.inner.kind {
            Kind::User(_) => true,
            _ => false,
        }
    }

    /// Returns true if this was about a `Request` that was canceled.
    pub fn is_canceled(&self) -> bool {
        self.inner.kind == Kind::Canceled
    }

    /// Returns true if a sender's channel is closed.
    pub fn is_closed(&self) -> bool {
        self.inner.kind == Kind::ChannelClosed
    }

    /// Returns true if this was an error from `Connect`.
    pub fn is_connect(&self) -> bool {
        self.inner.kind == Kind::Connect
    }

    /// Returns true if the connection closed before a message could complete.
    pub fn is_incomplete_message(&self) -> bool {
        self.inner.kind == Kind::IncompleteMessage
    }

    /// Returns true if the body write was aborted.
    pub fn is_body_write_aborted(&self) -> bool {
        self.inner.kind == Kind::BodyWriteAborted
    }

    /// Consumes the error, returning its cause.
    pub fn into_cause(self) -> Option<Box<dyn StdError + Send + Sync>> {
        self.inner.cause
    }

    pub(crate) fn new(kind: Kind) -> Error {
        Error {
            inner: Box::new(ErrorImpl {
                kind,
                cause: None,
            }),
        }
    }

    pub(crate) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {
        self.inner.cause = Some(cause.into());
        self
    }

    pub(crate) fn kind(&self) -> &Kind {
        &self.inner.kind
    }

    pub(crate) fn h2_reason(&self) -> h2::Reason {
        // Find an h2::Reason somewhere in the cause stack, if it exists,
        // otherwise assume an INTERNAL_ERROR.
        let mut cause = self.source();
        while let Some(err) = cause {
            if let Some(h2_err) = err.downcast_ref::<h2::Error>() {
                return h2_err
                    .reason()
                    .unwrap_or(h2::Reason::INTERNAL_ERROR);
            }
            cause = err.source();
        }

        // else
        h2::Reason::INTERNAL_ERROR
    }

    pub(crate) fn new_canceled() -> Error {
        Error::new(Kind::Canceled)
    }

    pub(crate) fn new_incomplete() -> Error {
        Error::new(Kind::IncompleteMessage)
    }

    pub(crate) fn new_too_large() -> Error {
        Error::new(Kind::Parse(Parse::TooLarge))
    }

    pub(crate) fn new_version_h2() -> Error {
        Error::new(Kind::Parse(Parse::VersionH2))
    }

    pub(crate) fn new_unexpected_message() -> Error {
        Error::new(Kind::UnexpectedMessage)
    }

    pub(crate) fn new_io(cause: io::Error) -> Error {
        Error::new(Kind::Io).with(cause)
    }

    #[cfg(feature = "tcp")]
    pub(crate) fn new_listen<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Listen).with(cause)
    }

    pub(crate) fn new_accept<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Accept).with(cause)
    }

    pub(crate) fn new_connect<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Connect).with(cause)
    }

    pub(crate) fn new_closed() -> Error {
        Error::new(Kind::ChannelClosed)
    }

    pub(crate) fn new_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Body).with(cause)
    }

    pub(crate) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::BodyWrite).with(cause)
    }

    pub(crate) fn new_body_write_aborted() -> Error {
        Error::new(Kind::BodyWriteAborted)
    }

    fn new_user(user: User) -> Error {
        Error::new(Kind::User(user))
    }

    pub(crate) fn new_user_header() -> Error {
        Error::new_user(User::UnexpectedHeader)
    }

    pub(crate) fn new_user_unsupported_version() -> Error {
        Error::new_user(User::UnsupportedVersion)
    }

    pub(crate) fn new_user_unsupported_request_method() -> Error {
        Error::new_user(User::UnsupportedRequestMethod)
    }

    pub(crate) fn new_user_unsupported_status_code() -> Error {
        Error::new_user(User::UnsupportedStatusCode)
    }

    pub(crate) fn new_user_absolute_uri_required() -> Error {
        Error::new_user(User::AbsoluteUriRequired)
    }

    pub(crate) fn new_user_no_upgrade() -> Error {
        Error::new_user(User::NoUpgrade)
    }

    pub(crate) fn new_user_manual_upgrade() -> Error {
        Error::new_user(User::ManualUpgrade)
    }

    pub(crate) fn new_user_make_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::MakeService).with(cause)
    }

    pub(crate) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::Service).with(cause)
    }

    pub(crate) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::Body).with(cause)
    }

    pub(crate) fn new_shutdown(cause: io::Error) -> Error {
        Error::new(Kind::Shutdown).with(cause)
    }

    pub(crate) fn new_execute<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::Execute).with(cause)
    }

    pub(crate) fn new_h2(cause: ::h2::Error) -> Error {
        if cause.is_io() {
            Error::new_io(cause.into_io().expect("h2::Error::is_io"))
        } else {
            Error::new(Kind::Http2).with(cause)
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut f = f.debug_tuple("Error");
        f.field(&self.inner.kind);
        if let Some(ref cause) = self.inner.cause {
            f.field(cause);
        }
        f.finish()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(ref cause) = self.inner.cause {
            write!(f, "{}: {}", self.description(), cause)
        } else {
            f.write_str(self.description())
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.inner.kind {
            Kind::Parse(Parse::Method) => "invalid HTTP method parsed",
            Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
            Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
            Kind::Parse(Parse::Uri) => "invalid URI",
            Kind::Parse(Parse::Header) => "invalid HTTP header parsed",
            Kind::Parse(Parse::TooLarge) => "message head is too large",
            Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed",
            Kind::IncompleteMessage => "connection closed before message completed",
            Kind::UnexpectedMessage => "received unexpected message from connection",
            Kind::ChannelClosed => "channel closed",
            Kind::Connect => "error trying to connect",
            Kind::Canceled => "operation was canceled",
            #[cfg(feature = "tcp")]
            Kind::Listen => "error creating server listener",
            Kind::Accept => "error accepting connection",
            Kind::Body => "error reading a body from connection",
            Kind::BodyWrite => "error writing a body to connection",
            Kind::BodyWriteAborted => "body write aborted",
            Kind::Shutdown => "error shutting down connection",
            Kind::Http2 => "http2 error",
            Kind::Io => "connection error",

            Kind::User(User::Body) => "error from user's Payload stream",
            Kind::User(User::MakeService) => "error from user's MakeService",
            Kind::User(User::Service) => "error from user's Service",
            Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
            Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version",
            Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method",
            Kind::User(User::UnsupportedStatusCode) => "response has 1xx status code, not supported by server",
            Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs",
            Kind::User(User::NoUpgrade) => "no upgrade available",
            Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use",
            Kind::User(User::Execute) => "executor failed to spawn task",
        }
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self
            .inner
            .cause
            .as_ref()
            .map(|cause| &**cause as &(dyn StdError + 'static))
    }
}

#[doc(hidden)]
impl From<Parse> for Error {
    fn from(err: Parse) -> Error {
        Error::new(Kind::Parse(err))
    }
}

impl From<httparse::Error> for Parse {
    fn from(err: httparse::Error) -> Parse {
        match err {
            httparse::Error::HeaderName |
            httparse::Error::HeaderValue |
            httparse::Error::NewLine |
            httparse::Error::Token => Parse::Header,
            httparse::Error::Status => Parse::Status,
            httparse::Error::TooManyHeaders => Parse::TooLarge,
            httparse::Error::Version => Parse::Version,
        }
    }
}

impl From<http::method::InvalidMethod> for Parse {
    fn from(_: http::method::InvalidMethod) -> Parse {
        Parse::Method
    }
}

impl From<http::status::InvalidStatusCode> for Parse {
    fn from(_: http::status::InvalidStatusCode) -> Parse {
        Parse::Status
    }
}

impl From<http::uri::InvalidUri> for Parse {
    fn from(_: http::uri::InvalidUri) -> Parse {
        Parse::Uri
    }
}

impl From<http::uri::InvalidUriBytes> for Parse {
    fn from(_: http::uri::InvalidUriBytes) -> Parse {
        Parse::Uri
    }
}

impl From<http::uri::InvalidUriParts> for Parse {
    fn from(_: http::uri::InvalidUriParts) -> Parse {
        Parse::Uri
    }
}

#[doc(hidden)]
trait AssertSendSync: Send + Sync + 'static {}
#[doc(hidden)]
impl AssertSendSync for Error {}

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

    #[test]
    fn error_size_of() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn h2_reason_unknown() {
        let closed = Error::new_closed();
        assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR);
    }

    #[test]
    fn h2_reason_one_level() {
        let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM));
        assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM);
    }

    #[test]
    fn h2_reason_nested() {
        let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED));
        // Suppose a user were proxying the received error
        let svc_err = Error::new_user_service(recvd);
        assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED);
    }
}
<commit_msg>refactor(error): update Debug for Error to output 'hyper::Error'<commit_after>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io;

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

type Cause = Box<dyn StdError + Send + Sync>;

/// Represents errors that can occur handling HTTP streams.
pub struct Error {
    inner: Box<ErrorImpl>,
}

struct ErrorImpl {
    kind: Kind,
    cause: Option<Cause>,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Kind {
    Parse(Parse),
    User(User),
    /// A message reached EOF, but is not complete.
    IncompleteMessage,
    /// A connection received a message (or bytes) when not waiting for one.
    UnexpectedMessage,
    /// A pending item was dropped before ever being processed.
    Canceled,
    /// Indicates a channel (client or body sender) is closed.
    ChannelClosed,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io,
    /// Error occurred while connecting.
    Connect,
    /// Error creating a TcpListener.
    #[cfg(feature = "tcp")]
    Listen,
    /// Error accepting on an Incoming stream.
    Accept,
    /// Error while reading a body from connection.
    Body,
    /// Error while writing a body to connection.
    BodyWrite,
    /// The body write was aborted.
    BodyWriteAborted,
    /// Error calling AsyncWrite::shutdown()
    Shutdown,

    /// A general error from h2.
    Http2,
}

#[derive(Debug, PartialEq)]
pub(crate) enum Parse {
    Method,
    Version,
    VersionH2,
    Uri,
    Header,
    TooLarge,
    Status,
}

#[derive(Debug, PartialEq)]
pub(crate) enum User {
    /// Error calling user's Payload::poll_data().
    Body,
    /// Error calling user's MakeService.
    MakeService,
    /// Error from future of user's Service.
    Service,
    /// User tried to send a certain header in an unexpected context.
    ///
    /// For example, sending both `content-length` and `transfer-encoding`.
    UnexpectedHeader,
    /// User tried to create a Request with bad version.
    UnsupportedVersion,
    /// User tried to create a CONNECT Request with the Client.
    UnsupportedRequestMethod,
    /// User tried to respond with a 1xx (not 101) response code.
    UnsupportedStatusCode,
    /// User tried to send a Request with Client with non-absolute URI.
    AbsoluteUriRequired,

    /// User tried polling for an upgrade that doesn't exist.
    NoUpgrade,

    /// User polled for an upgrade, but low-level API is not using upgrades.
    ManualUpgrade,

    /// Error trying to call `Executor::execute`.
    Execute,
}

impl Error {
    /// Returns true if this was an HTTP parse error.
    pub fn is_parse(&self) -> bool {
        match self.inner.kind {
            Kind::Parse(_) => true,
            _ => false,
        }
    }

    /// Returns true if this error was caused by user code.
    pub fn is_user(&self) -> bool {
        match self.inner.kind {
            Kind::User(_) => true,
            _ => false,
        }
    }

    /// Returns true if this was about a `Request` that was canceled.
    pub fn is_canceled(&self) -> bool {
        self.inner.kind == Kind::Canceled
    }

    /// Returns true if a sender's channel is closed.
    pub fn is_closed(&self) -> bool {
        self.inner.kind == Kind::ChannelClosed
    }

    /// Returns true if this was an error from `Connect`.
    pub fn is_connect(&self) -> bool {
        self.inner.kind == Kind::Connect
    }

    /// Returns true if the connection closed before a message could complete.
    pub fn is_incomplete_message(&self) -> bool {
        self.inner.kind == Kind::IncompleteMessage
    }

    /// Returns true if the body write was aborted.
    pub fn is_body_write_aborted(&self) -> bool {
        self.inner.kind == Kind::BodyWriteAborted
    }

    /// Consumes the error, returning its cause.
    pub fn into_cause(self) -> Option<Box<dyn StdError + Send + Sync>> {
        self.inner.cause
    }

    pub(crate) fn new(kind: Kind) -> Error {
        Error {
            inner: Box::new(ErrorImpl {
                kind,
                cause: None,
            }),
        }
    }

    pub(crate) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {
        self.inner.cause = Some(cause.into());
        self
    }

    pub(crate) fn kind(&self) -> &Kind {
        &self.inner.kind
    }

    pub(crate) fn h2_reason(&self) -> h2::Reason {
        // Find an h2::Reason somewhere in the cause stack, if it exists,
        // otherwise assume an INTERNAL_ERROR.
        let mut cause = self.source();
        while let Some(err) = cause {
            if let Some(h2_err) = err.downcast_ref::<h2::Error>() {
                return h2_err
                    .reason()
                    .unwrap_or(h2::Reason::INTERNAL_ERROR);
            }
            cause = err.source();
        }

        // else
        h2::Reason::INTERNAL_ERROR
    }

    pub(crate) fn new_canceled() -> Error {
        Error::new(Kind::Canceled)
    }

    pub(crate) fn new_incomplete() -> Error {
        Error::new(Kind::IncompleteMessage)
    }

    pub(crate) fn new_too_large() -> Error {
        Error::new(Kind::Parse(Parse::TooLarge))
    }

    pub(crate) fn new_version_h2() -> Error {
        Error::new(Kind::Parse(Parse::VersionH2))
    }

    pub(crate) fn new_unexpected_message() -> Error {
        Error::new(Kind::UnexpectedMessage)
    }

    pub(crate) fn new_io(cause: io::Error) -> Error {
        Error::new(Kind::Io).with(cause)
    }

    #[cfg(feature = "tcp")]
    pub(crate) fn new_listen<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Listen).with(cause)
    }

    pub(crate) fn new_accept<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Accept).with(cause)
    }

    pub(crate) fn new_connect<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Connect).with(cause)
    }

    pub(crate) fn new_closed() -> Error {
        Error::new(Kind::ChannelClosed)
    }

    pub(crate) fn new_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::Body).with(cause)
    }

    pub(crate) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
        Error::new(Kind::BodyWrite).with(cause)
    }

    pub(crate) fn new_body_write_aborted() -> Error {
        Error::new(Kind::BodyWriteAborted)
    }

    fn new_user(user: User) -> Error {
        Error::new(Kind::User(user))
    }

    pub(crate) fn new_user_header() -> Error {
        Error::new_user(User::UnexpectedHeader)
    }

    pub(crate) fn new_user_unsupported_version() -> Error {
        Error::new_user(User::UnsupportedVersion)
    }

    pub(crate) fn new_user_unsupported_request_method() -> Error {
        Error::new_user(User::UnsupportedRequestMethod)
    }

    pub(crate) fn new_user_unsupported_status_code() -> Error {
        Error::new_user(User::UnsupportedStatusCode)
    }

    pub(crate) fn new_user_absolute_uri_required() -> Error {
        Error::new_user(User::AbsoluteUriRequired)
    }

    pub(crate) fn new_user_no_upgrade() -> Error {
        Error::new_user(User::NoUpgrade)
    }

    pub(crate) fn new_user_manual_upgrade() -> Error {
        Error::new_user(User::ManualUpgrade)
    }

    pub(crate) fn new_user_make_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::MakeService).with(cause)
    }

    pub(crate) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::Service).with(cause)
    }

    pub(crate) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::Body).with(cause)
    }

    pub(crate) fn new_shutdown(cause: io::Error) -> Error {
        Error::new(Kind::Shutdown).with(cause)
    }

    pub(crate) fn new_execute<E: Into<Cause>>(cause: E) -> Error {
        Error::new_user(User::Execute).with(cause)
    }

    pub(crate) fn new_h2(cause: ::h2::Error) -> Error {
        if cause.is_io() {
            Error::new_io(cause.into_io().expect("h2::Error::is_io"))
        } else {
            Error::new(Kind::Http2).with(cause)
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut f = f.debug_tuple("hyper::Error");
        f.field(&self.inner.kind);
        if let Some(ref cause) = self.inner.cause {
            f.field(cause);
        }
        f.finish()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(ref cause) = self.inner.cause {
            write!(f, "{}: {}", self.description(), cause)
        } else {
            f.write_str(self.description())
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.inner.kind {
            Kind::Parse(Parse::Method) => "invalid HTTP method parsed",
            Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
            Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
            Kind::Parse(Parse::Uri) => "invalid URI",
            Kind::Parse(Parse::Header) => "invalid HTTP header parsed",
            Kind::Parse(Parse::TooLarge) => "message head is too large",
            Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed",
            Kind::IncompleteMessage => "connection closed before message completed",
            Kind::UnexpectedMessage => "received unexpected message from connection",
            Kind::ChannelClosed => "channel closed",
            Kind::Connect => "error trying to connect",
            Kind::Canceled => "operation was canceled",
            #[cfg(feature = "tcp")]
            Kind::Listen => "error creating server listener",
            Kind::Accept => "error accepting connection",
            Kind::Body => "error reading a body from connection",
            Kind::BodyWrite => "error writing a body to connection",
            Kind::BodyWriteAborted => "body write aborted",
            Kind::Shutdown => "error shutting down connection",
            Kind::Http2 => "http2 error",
            Kind::Io => "connection error",

            Kind::User(User::Body) => "error from user's Payload stream",
            Kind::User(User::MakeService) => "error from user's MakeService",
            Kind::User(User::Service) => "error from user's Service",
            Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
            Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version",
            Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method",
            Kind::User(User::UnsupportedStatusCode) => "response has 1xx status code, not supported by server",
            Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs",
            Kind::User(User::NoUpgrade) => "no upgrade available",
            Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use",
            Kind::User(User::Execute) => "executor failed to spawn task",
        }
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self
            .inner
            .cause
            .as_ref()
            .map(|cause| &**cause as &(dyn StdError + 'static))
    }
}

#[doc(hidden)]
impl From<Parse> for Error {
    fn from(err: Parse) -> Error {
        Error::new(Kind::Parse(err))
    }
}

impl From<httparse::Error> for Parse {
    fn from(err: httparse::Error) -> Parse {
        match err {
            httparse::Error::HeaderName |
            httparse::Error::HeaderValue |
            httparse::Error::NewLine |
            httparse::Error::Token => Parse::Header,
            httparse::Error::Status => Parse::Status,
            httparse::Error::TooManyHeaders => Parse::TooLarge,
            httparse::Error::Version => Parse::Version,
        }
    }
}

impl From<http::method::InvalidMethod> for Parse {
    fn from(_: http::method::InvalidMethod) -> Parse {
        Parse::Method
    }
}

impl From<http::status::InvalidStatusCode> for Parse {
    fn from(_: http::status::InvalidStatusCode) -> Parse {
        Parse::Status
    }
}

impl From<http::uri::InvalidUri> for Parse {
    fn from(_: http::uri::InvalidUri) -> Parse {
        Parse::Uri
    }
}

impl From<http::uri::InvalidUriBytes> for Parse {
    fn from(_: http::uri::InvalidUriBytes) -> Parse {
        Parse::Uri
    }
}

impl From<http::uri::InvalidUriParts> for Parse {
    fn from(_: http::uri::InvalidUriParts) -> Parse {
        Parse::Uri
    }
}

#[doc(hidden)]
trait AssertSendSync: Send + Sync + 'static {}
#[doc(hidden)]
impl AssertSendSync for Error {}

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

    #[test]
    fn error_size_of() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn h2_reason_unknown() {
        let closed = Error::new_closed();
        assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR);
    }

    #[test]
    fn h2_reason_one_level() {
        let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM));
        assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM);
    }

    #[test]
    fn h2_reason_nested() {
        let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED));
        // Suppose a user were proxying the received error
        let svc_err = Error::new_user_service(recvd);
        assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED);
    }
}
<|endoftext|>