<commit_before>use std::{fmt, result, str, error as std_error};
use std::io::{Result, Read, Error, ErrorKind};

pub trait CharsExt {
    fn chars_iterator(self) -> Chars<Self> where Self: Sized {
        Chars { inner: self }
    }
}

impl<T: Read> CharsExt for T {

}

#[derive(Debug)]
pub struct Chars<R> {
    inner: R,
}

/// An enumeration of possible errors that can be generated from the `Chars`
/// adapter.
#[derive(Debug)]
pub enum CharsError {
    /// Variant representing that the underlying stream was read successfully
    /// but it did not contain valid utf8 data.
    NotUtf8,

    /// Variant representing that an I/O error occurred.
    Other(Error),
}

impl<R: Read> Iterator for Chars<R> {
    type Item = result::Result<char, CharsError>;

    fn next(&mut self) -> Option<result::Result<char, CharsError>> {
        let first_byte = match read_one_byte(&mut self.inner)? {
            Ok(b) => b,
            Err(e) => return Some(Err(CharsError::Other(e))),
        };
        let width = utf8_char_width(first_byte);
        if width == 1 { return Some(Ok(first_byte as char)) }
        if width == 0 { return Some(Err(CharsError::NotUtf8)) }
        let mut buf = [first_byte, 0, 0, 0];
        {
            let mut start = 1;
            while start < width {
                match self.inner.read(&mut buf[start..width]) {
                    Ok(0) => return Some(Err(CharsError::NotUtf8)),
                    Ok(n) => start += n,
                    Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                    Err(e) => return Some(Err(CharsError::Other(e))),
                }
            }
        }
        Some(match str::from_utf8(&buf[..width]).ok() {
            Some(s) => Ok(s.chars().next().unwrap()),
            None => Err(CharsError::NotUtf8),
        })
    }
}

impl std_error::Error for CharsError {
    fn description(&self) -> &str {
        match *self {
            CharsError::NotUtf8 => "invalid utf8 encoding",
            CharsError::Other(ref e) => std_error::Error::description(e),
        }
    }
    fn cause(&self) -> Option<&std_error::Error> {
        match *self {
            CharsError::NotUtf8 => None,
            CharsError::Other(ref e) => e.cause(),
        }
    }
}

impl fmt::Display for CharsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CharsError::NotUtf8 => {
                "byte stream did not contain valid utf8".fmt(f)
            }
            CharsError::Other(ref e) => e.fmt(f),
        }
    }
}

fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
    let mut buf = [0];
    loop {
        return match reader.read(&mut buf) {
            Ok(0) => None,
            Ok(..) => Some(Ok(buf[0])),
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => Some(Err(e)),
        };
    }
}

/// Given a first byte, determines how many bytes are in this UTF-8 character.
#[inline]
pub fn utf8_char_width(b: u8) -> usize {
    match b {
        0...0x7f => 1,
        0xc2...0xdf => 2,
        0xe0...0xef => 3,
        0xf0...0xf4 => 4,
        0x80...0xc1 | 0xf5...0xff => 0,
        _ => unreachable!(),
    }
}

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

    use std::io::Cursor;

    // https://tools.ietf.org/html/rfc3629
    static UTF8_CHAR_WIDTH: [u8; 256] = [
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF
        0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF
        4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF
    ];

    #[test]
    pub fn char_width() {
        for i in 0..=255 {
            assert_eq!(super::utf8_char_width(i) as u8, UTF8_CHAR_WIDTH[i as usize]);
        }
    }

    #[test]
    fn chars_iterator_works() {
        let s = "hello, I'm cool".to_owned();

        let c = Cursor::new(s.clone().into_bytes());

        let v: Vec<char> = c.chars_iterator().flat_map(Result::ok).collect();
        let v2: Vec<char> = s.chars().collect();
        assert_eq!(v, v2);
    }
}
<commit_msg>Better test in chars.rs<commit_after>use std::{fmt, result, str, error as std_error};
use std::io::{Result, Read, Error, ErrorKind};

pub trait CharsExt {
    fn chars_iterator(self) -> Chars<Self> where Self: Sized {
        Chars { inner: self }
    }
}

impl<T: Read> CharsExt for T {

}

#[derive(Debug)]
pub struct Chars<R> {
    inner: R,
}

/// An enumeration of possible errors that can be generated from the `Chars`
/// adapter.
#[derive(Debug)]
pub enum CharsError {
    /// Variant representing that the underlying stream was read successfully
    /// but it did not contain valid utf8 data.
    NotUtf8,

    /// Variant representing that an I/O error occurred.
    Other(Error),
}

impl<R: Read> Iterator for Chars<R> {
    type Item = result::Result<char, CharsError>;

    fn next(&mut self) -> Option<result::Result<char, CharsError>> {
        let first_byte = match read_one_byte(&mut self.inner)? {
            Ok(b) => b,
            Err(e) => return Some(Err(CharsError::Other(e))),
        };
        let width = utf8_char_width(first_byte);
        if width == 1 { return Some(Ok(first_byte as char)) }
        if width == 0 { return Some(Err(CharsError::NotUtf8)) }
        let mut buf = [first_byte, 0, 0, 0];
        {
            let mut start = 1;
            while start < width {
                match self.inner.read(&mut buf[start..width]) {
                    Ok(0) => return Some(Err(CharsError::NotUtf8)),
                    Ok(n) => start += n,
                    Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                    Err(e) => return Some(Err(CharsError::Other(e))),
                }
            }
        }
        Some(match str::from_utf8(&buf[..width]).ok() {
            Some(s) => Ok(s.chars().next().unwrap()),
            None => Err(CharsError::NotUtf8),
        })
    }
}

impl std_error::Error for CharsError {
    fn description(&self) -> &str {
        match *self {
            CharsError::NotUtf8 => "invalid utf8 encoding",
            CharsError::Other(ref e) => std_error::Error::description(e),
        }
    }
    fn cause(&self) -> Option<&std_error::Error> {
        match *self {
            CharsError::NotUtf8 => None,
            CharsError::Other(ref e) => e.cause(),
        }
    }
}

impl fmt::Display for CharsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CharsError::NotUtf8 => {
                "byte stream did not contain valid utf8".fmt(f)
            }
            CharsError::Other(ref e) => e.fmt(f),
        }
    }
}

fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
    let mut buf = [0];
    loop {
        return match reader.read(&mut buf) {
            Ok(0) => None,
            Ok(..) => Some(Ok(buf[0])),
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => Some(Err(e)),
        };
    }
}

/// Given a first byte, determines how many bytes are in this UTF-8 character.
#[inline]
pub fn utf8_char_width(b: u8) -> usize {
    match b {
        0...0x7f => 1,
        0xc2...0xdf => 2,
        0xe0...0xef => 3,
        0xf0...0xf4 => 4,
        0x80...0xc1 | 0xf5...0xff => 0,
        _ => unreachable!(),
    }
}

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

    use std::io::Cursor;

    // https://tools.ietf.org/html/rfc3629
    static UTF8_CHAR_WIDTH: [u8; 256] = [
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF
        0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF
        4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF
    ];

    #[test]
    pub fn char_width() {
        for i in 0..=255 {
            assert_eq!(super::utf8_char_width(i) as u8, UTF8_CHAR_WIDTH[i as usize]);
        }
    }

    #[test]
    fn chars_iterator_works() {
        let s = "ħɛlɭoʊ, Ï'ˀm̃ c̈₀⁰ɫ".to_owned();

        let c = Cursor::new(s.clone().into_bytes());

        let v: Vec<char> = c.chars_iterator().flat_map(Result::ok).collect();
        let v2: Vec<char> = s.chars().collect();
        assert_eq!(v, v2);
    }
}
<|endoftext|>


<commit_before>//! This module provides a bit reader

use std::io;
use std::io::{Read, Write};
use byteorder::ReadBytesExt;

/// Bit reader
pub trait BitReader: Read {
    /// Returns the next `n` bits.
    fn read_bits(&mut self, n: u8) -> io::Result<u16>;
}

/// Bit writer
pub trait BitWriter: Write {
    /// Writes the next `n` bits.
    fn write_bits(&mut self, v: u16, n: u8) -> io::Result<()>;
}

macro_rules! define_bit_readers {
    {$(
        $name:ident, #[$doc:meta];
    )*} => {

$( // START Structure definitions

#[$doc]
pub struct $name<R> where R: Read {
    r: R,
    bits: u8,
    acc: u32,
}

impl<R: Read> $name<R> {

    /// Creates a new bit reader
    pub fn new(reader: R) -> $name<R> {
        $name {
            r: reader,
            bits: 0,
            acc: 0,
        }
    }

    /// Returns true if the reader is aligned to a byte of the underlying byte stream.
    #[inline(always)]
    fn is_aligned(&self) -> bool {
        self.bits == 0
    }

}

impl<R: Read> Read for $name<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.is_aligned() {
            self.r.read(buf)
        } else {
            let mut i = 0;
            for (j, byte) in buf.iter_mut().enumerate() {
                *byte = try!(self.read_bits(8)) as u8;
                i = j;
            }
            Ok(i)
        }
    }
}

)* // END Structure definitions

    }
}

define_bit_readers!{
    LsbReader, #[doc = "Reads bits from a byte stream, LSB first."];
    MsbReader, #[doc = "Reads bits from a byte stream, MSB first."];
}

impl<R> BitReader for LsbReader<R> where R: Read {

    fn read_bits(&mut self, n: u8) -> io::Result<u16> {
        if n > 16 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Cannot read more than 16 bits",
                None
            ))
        }
        while self.bits < n {
            self.acc |= (try!(self.r.read_u8()) as u32) << self.bits;
            self.bits += 8;
        }
        let res = self.acc & ((1 << n) - 1);
        self.acc >>= n;
        self.bits -= n;
        Ok(res as u16)
    }

}

impl<R> BitReader for MsbReader<R> where R: Read {

    fn read_bits(&mut self, n: u8) -> io::Result<u16> {
        if n > 16 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Cannot read more than 16 bits",
                None
            ))
        }
        while self.bits < n {
            self.acc |= (try!(self.r.read_u8()) as u32) << (24 - self.bits);
            self.bits += 8;
        }
        let res = self.acc >> (32 - n);
        self.acc <<= n;
        self.bits -= n;
        Ok(res as u16)
    }
}

macro_rules! define_bit_writers {
    {$(
        $name:ident, #[$doc:meta];
    )*} => {

$( // START Structure definitions

#[$doc]
#[allow(dead_code)]
pub struct $name<'a, W> where W: Write + 'a {
    w: &'a mut W,
    bits: u8,
    acc: u32,
}

impl<'a, W> $name<'a, W> where W: Write + 'a  {
    /// Creates a new bit reader
    #[allow(dead_code)]
    pub fn new(writer: &'a mut W) -> $name<'a, W> {
        $name {
            w: writer,
            bits: 0,
            acc: 0,
        }
    }
}

impl<'a, W> Write for $name<'a, W> where W: Write + 'a  {

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.acc == 0 {
            self.w.write(buf)
        } else {
            for &byte in buf.iter() {
                try!(self.write_bits(byte as u16, 8))
            }
            Ok(buf.len())
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        let missing = 8 - self.bits;
        if missing > 0 {
            try!(self.write_bits(0, missing));
        }
        self.w.flush()
    }
}

)* // END Structure definitions

    }
}

define_bit_writers!{
    LsbWriter, #[doc = "Writes bits to a byte stream, LSB first."];
    MsbWriter, #[doc = "Writes bits to a byte stream, MSB first."];
}

impl<'a, W> BitWriter for LsbWriter<'a, W> where W: Write + 'a  {

    fn write_bits(&mut self, v: u16, n: u8) -> io::Result<()> {
        self.acc |= (v as u32) << self.bits;
        self.bits += n;
        while self.bits >= 8 {
            try!(self.w.write_all(&[self.acc as u8]));
            self.acc >>= 8;
            self.bits -= 8

        }
        Ok(())
    }

}

impl<'a, W> BitWriter for MsbWriter<'a, W> where W: Write + 'a  {

    fn write_bits(&mut self, v: u16, n: u8) -> io::Result<()> {
        self.acc |= (v as u32) << (32 - n - self.bits);
        self.bits += n;
        while self.bits >= 8 {
            try!(self.w.write_all(&[(self.acc >> 24) as u8]));
            self.acc <<= 8;
            self.bits -= 8

        }
        Ok(())
    }

}

#[cfg(test)]
mod test {
    use super::{BitReader, BitWriter};

    #[test]
    fn reader_writer() {
        let data = [255, 20, 40, 120, 128];
        let mut expanded_data = Vec::new();
        let mut reader = super::LsbReader::new(&data[..]);
        while let Ok(b) = reader.read_bits(10) {
            expanded_data.push(b)
        }
        let mut compressed_data = Vec::new();
        {
            let mut writer = super::LsbWriter::new(&mut compressed_data);
            for &datum in expanded_data.iter() {
                let _  = writer.write_bits(datum, 10);
            }
        }
        assert_eq!(&data, &compressed_data)
    }
}
<commit_msg>Switch assert_eq! order, since &[T] == Vec<T> no longer compiles<commit_after>//! This module provides a bit reader

use std::io;
use std::io::{Read, Write};
use byteorder::ReadBytesExt;

/// Bit reader
pub trait BitReader: Read {
    /// Returns the next `n` bits.
    fn read_bits(&mut self, n: u8) -> io::Result<u16>;
}

/// Bit writer
pub trait BitWriter: Write {
    /// Writes the next `n` bits.
    fn write_bits(&mut self, v: u16, n: u8) -> io::Result<()>;
}

macro_rules! define_bit_readers {
    {$(
        $name:ident, #[$doc:meta];
    )*} => {

$( // START Structure definitions

#[$doc]
pub struct $name<R> where R: Read {
    r: R,
    bits: u8,
    acc: u32,
}

impl<R: Read> $name<R> {

    /// Creates a new bit reader
    pub fn new(reader: R) -> $name<R> {
        $name {
            r: reader,
            bits: 0,
            acc: 0,
        }
    }

    /// Returns true if the reader is aligned to a byte of the underlying byte stream.
    #[inline(always)]
    fn is_aligned(&self) -> bool {
        self.bits == 0
    }

}

impl<R: Read> Read for $name<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.is_aligned() {
            self.r.read(buf)
        } else {
            let mut i = 0;
            for (j, byte) in buf.iter_mut().enumerate() {
                *byte = try!(self.read_bits(8)) as u8;
                i = j;
            }
            Ok(i)
        }
    }
}

)* // END Structure definitions

    }
}

define_bit_readers!{
    LsbReader, #[doc = "Reads bits from a byte stream, LSB first."];
    MsbReader, #[doc = "Reads bits from a byte stream, MSB first."];
}

impl<R> BitReader for LsbReader<R> where R: Read {

    fn read_bits(&mut self, n: u8) -> io::Result<u16> {
        if n > 16 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Cannot read more than 16 bits",
                None
            ))
        }
        while self.bits < n {
            self.acc |= (try!(self.r.read_u8()) as u32) << self.bits;
            self.bits += 8;
        }
        let res = self.acc & ((1 << n) - 1);
        self.acc >>= n;
        self.bits -= n;
        Ok(res as u16)
    }

}

impl<R> BitReader for MsbReader<R> where R: Read {

    fn read_bits(&mut self, n: u8) -> io::Result<u16> {
        if n > 16 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Cannot read more than 16 bits",
                None
            ))
        }
        while self.bits < n {
            self.acc |= (try!(self.r.read_u8()) as u32) << (24 - self.bits);
            self.bits += 8;
        }
        let res = self.acc >> (32 - n);
        self.acc <<= n;
        self.bits -= n;
        Ok(res as u16)
    }
}

macro_rules! define_bit_writers {
    {$(
        $name:ident, #[$doc:meta];
    )*} => {

$( // START Structure definitions

#[$doc]
#[allow(dead_code)]
pub struct $name<'a, W> where W: Write + 'a {
    w: &'a mut W,
    bits: u8,
    acc: u32,
}

impl<'a, W> $name<'a, W> where W: Write + 'a  {
    /// Creates a new bit reader
    #[allow(dead_code)]
    pub fn new(writer: &'a mut W) -> $name<'a, W> {
        $name {
            w: writer,
            bits: 0,
            acc: 0,
        }
    }
}

impl<'a, W> Write for $name<'a, W> where W: Write + 'a  {

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.acc == 0 {
            self.w.write(buf)
        } else {
            for &byte in buf.iter() {
                try!(self.write_bits(byte as u16, 8))
            }
            Ok(buf.len())
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        let missing = 8 - self.bits;
        if missing > 0 {
            try!(self.write_bits(0, missing));
        }
        self.w.flush()
    }
}

)* // END Structure definitions

    }
}

define_bit_writers!{
    LsbWriter, #[doc = "Writes bits to a byte stream, LSB first."];
    MsbWriter, #[doc = "Writes bits to a byte stream, MSB first."];
}

impl<'a, W> BitWriter for LsbWriter<'a, W> where W: Write + 'a  {

    fn write_bits(&mut self, v: u16, n: u8) -> io::Result<()> {
        self.acc |= (v as u32) << self.bits;
        self.bits += n;
        while self.bits >= 8 {
            try!(self.w.write_all(&[self.acc as u8]));
            self.acc >>= 8;
            self.bits -= 8

        }
        Ok(())
    }

}

impl<'a, W> BitWriter for MsbWriter<'a, W> where W: Write + 'a  {

    fn write_bits(&mut self, v: u16, n: u8) -> io::Result<()> {
        self.acc |= (v as u32) << (32 - n - self.bits);
        self.bits += n;
        while self.bits >= 8 {
            try!(self.w.write_all(&[(self.acc >> 24) as u8]));
            self.acc <<= 8;
            self.bits -= 8

        }
        Ok(())
    }

}

#[cfg(test)]
mod test {
    use super::{BitReader, BitWriter};

    #[test]
    fn reader_writer() {
        let data = [255, 20, 40, 120, 128];
        let mut expanded_data = Vec::new();
        let mut reader = super::LsbReader::new(&data[..]);
        while let Ok(b) = reader.read_bits(10) {
            expanded_data.push(b)
        }
        let mut compressed_data = Vec::new();
        {
            let mut writer = super::LsbWriter::new(&mut compressed_data);
            for &datum in expanded_data.iter() {
                let _  = writer.write_bits(datum, 10);
            }
        }
        assert_eq!(&compressed_data, &data)
    }
}
<|endoftext|>


<commit_before>use std::mem::size_of;
use std::os::raw::{c_int, c_long, c_longlong, c_short, c_uint, c_ulong, c_ulonglong, c_ushort};

use cfg_if::cfg_if;
use num_traits::{Bounded, Zero};
use pyo3::{ffi, prelude::*, pyobject_native_type_core, types::PyType, AsPyPointer, PyNativeType};

use crate::npyffi::{NpyTypes, PyArray_Descr, NPY_TYPES, PY_ARRAY_API};

pub use num_complex::{Complex32, Complex64};

/// Binding of [`numpy.dtype`](https://numpy.org/doc/stable/reference/generated/numpy.dtype.html).
///
/// # Example
/// ```
/// use pyo3::types::IntoPyDict;
/// pyo3::Python::with_gil(|py| {
///     let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
///     let dtype: &numpy::PyArrayDescr = py
///         .eval("np.array([1, 2, 3.0]).dtype", Some(locals), None)
///         .unwrap()
///         .downcast()
///         .unwrap();
///     assert!(dtype.is_equiv_to(numpy::PyArrayDescr::of::<f64>(py)));
/// });
/// ```
pub struct PyArrayDescr(PyAny);

pyobject_native_type_core!(
    PyArrayDescr,
    *PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    #module=Some("numpy"),
    #checkfunction=arraydescr_check
);

unsafe fn arraydescr_check(op: *mut ffi::PyObject) -> c_int {
    ffi::PyObject_TypeCheck(
        op,
        PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    )
}

impl PyArrayDescr {
    /// Returns `self` as `*mut PyArray_Descr`.
    pub fn as_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.as_ptr() as _
    }

    /// Returns `self` as `*mut PyArray_Descr` while increasing the reference count.
    ///
    /// Useful in cases where the descriptor is stolen by the API.
    pub fn into_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.into_ptr() as _
    }

    /// Returns the internal `PyType` that this `dtype` holds.
    ///
    /// # Example
    /// ```
    /// pyo3::Python::with_gil(|py| {
    ///    let array = numpy::PyArray::from_vec(py, vec![0.0, 1.0, 2.0f64]);
    ///    let dtype = array.dtype();
    ///    assert_eq!(dtype.get_type().name().unwrap().to_string(), "float64");
    /// });
    /// ```
    pub fn get_type(&self) -> &PyType {
        let dtype_type_ptr = unsafe { *self.as_dtype_ptr() }.typeobj;
        unsafe { PyType::from_type_ptr(self.py(), dtype_type_ptr) }
    }

    /// Shortcut for creating a descriptor of 'object' type.
    pub fn object(py: Python) -> &Self {
        Self::from_npy_type(py, NPY_TYPES::NPY_OBJECT)
    }

    /// Returns the type descriptor for a registered type.
    pub fn of<T: Element>(py: Python) -> &Self {
        T::get_dtype(py)
    }

    /// Returns true if two type descriptors are equivalent.
    pub fn is_equiv_to(&self, other: &Self) -> bool {
        unsafe { PY_ARRAY_API.PyArray_EquivTypes(self.as_dtype_ptr(), other.as_dtype_ptr()) != 0 }
    }

    fn from_npy_type(py: Python, npy_type: NPY_TYPES) -> &Self {
        unsafe {
            let descr = PY_ARRAY_API.PyArray_DescrFromType(npy_type as _);
            py.from_owned_ptr(descr as _)
        }
    }

    /// Retrieves the
    /// [enumerated type](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
    /// for this type descriptor.
    pub fn get_typenum(&self) -> c_int {
        unsafe { *self.as_dtype_ptr() }.type_num
    }
}

/// Represents that a type can be an element of `PyArray`.
///
/// Currently, only integer/float/complex types are supported.
/// If you come up with a nice implementation for some other types, we're happy to receive your PR :)
/// You may refer to the [numpy document](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
/// for all types that numpy supports.
///
/// # Safety
///
/// A type `T` that implements this trait should be safe when managed in numpy array,
/// thus implementing this trait is marked unsafe.
/// This means that all data types except for `DataType::Object` are assumed to be trivially copyable.
/// Furthermore, it is assumed that for `DataType::Object` the elements are pointers into the Python heap
/// and that the corresponding `Clone` implemenation will never panic as it only increases the reference count.
///
/// # Custom element types
///
/// You can implement this trait to manage arrays of custom element types, but they still need to be stored
/// on Python's heap using PyO3's [Py](pyo3::Py) type.
///
/// ```
/// use numpy::{ndarray::Array2, Element, PyArray, PyArrayDescr, ToPyArray};
/// use pyo3::{pyclass, Py, Python};
///
/// #[pyclass]
/// pub struct CustomElement;
///
/// // The transparent wrapper is necessary as one cannot implement
/// // a foreign trait (`Element`) on a foreign type (`Py`) directly.
/// #[derive(Clone)]
/// #[repr(transparent)]
/// pub struct Wrapper(pub Py<CustomElement>);
///
/// unsafe impl Element for Wrapper {
///     const IS_COPY: bool = false;
///
///     fn get_dtype(py: Python) -> &PyArrayDescr {
///         PyArrayDescr::object(py)
///     }
/// }
///
/// Python::with_gil(|py| {
///     let array = Array2::<Wrapper>::from_shape_fn((2, 3), |(_i, _j)| {
///         Wrapper(Py::new(py, CustomElement).unwrap())
///     });
///
///     let _array: &PyArray<Wrapper, _> = array.to_pyarray(py);
/// });
/// ```
pub unsafe trait Element: Clone + Send {
    /// Flag that indicates whether this type is trivially copyable.
    ///
    /// It should be set to true for all trivially copyable types (like scalar types
    /// and record/array types only containing trivially copyable fields and elements).
    ///
    /// This flag should *always* be set to `false` for object types or record types
    /// that contain object-type fields.
    const IS_COPY: bool;

    /// Returns the associated array descriptor ("dtype") for the given type.
    fn get_dtype(py: Python) -> &PyArrayDescr;
}

fn npy_int_type_lookup<T, T0, T1, T2>(npy_types: [NPY_TYPES; 3]) -> NPY_TYPES {
    // `npy_common.h` defines the integer aliases. In order, it checks:
    // NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR
    // and assigns the alias to the first matching size, so we should check in this order.
    match size_of::<T>() {
        x if x == size_of::<T0>() => npy_types[0],
        x if x == size_of::<T1>() => npy_types[1],
        x if x == size_of::<T2>() => npy_types[2],
        _ => panic!("Unable to match integer type descriptor: {:?}", npy_types),
    }
}

fn npy_int_type<T: Bounded + Zero + Sized + PartialEq>() -> NPY_TYPES {
    let is_unsigned = T::min_value() == T::zero();
    let bit_width = size_of::<T>() << 3;

    match (is_unsigned, bit_width) {
        (false, 8) => NPY_TYPES::NPY_BYTE,
        (false, 16) => NPY_TYPES::NPY_SHORT,
        (false, 32) => npy_int_type_lookup::<i32, c_long, c_int, c_short>([
            NPY_TYPES::NPY_LONG,
            NPY_TYPES::NPY_INT,
            NPY_TYPES::NPY_SHORT,
        ]),
        (false, 64) => npy_int_type_lookup::<i64, c_long, c_longlong, c_int>([
            NPY_TYPES::NPY_LONG,
            NPY_TYPES::NPY_LONGLONG,
            NPY_TYPES::NPY_INT,
        ]),
        (true, 8) => NPY_TYPES::NPY_UBYTE,
        (true, 16) => NPY_TYPES::NPY_USHORT,
        (true, 32) => npy_int_type_lookup::<u32, c_ulong, c_uint, c_ushort>([
            NPY_TYPES::NPY_ULONG,
            NPY_TYPES::NPY_UINT,
            NPY_TYPES::NPY_USHORT,
        ]),
        (true, 64) => npy_int_type_lookup::<u64, c_ulong, c_ulonglong, c_uint>([
            NPY_TYPES::NPY_ULONG,
            NPY_TYPES::NPY_ULONGLONG,
            NPY_TYPES::NPY_UINT,
        ]),
        _ => unreachable!(),
    }
}

macro_rules! impl_element_scalar {
    (@impl: $ty:ty, $npy_type:expr $(,#[$meta:meta])*) => {
        $(#[$meta])*
        unsafe impl Element for $ty {
            const IS_COPY: bool = true;
            fn get_dtype(py: Python) -> &PyArrayDescr {
                PyArrayDescr::from_npy_type(py, $npy_type)
            }
        }
    };
    ($ty:ty, $npy_type:ident $(,#[$meta:meta])*) => {
        impl_element_scalar!(@impl: $ty, NPY_TYPES::$npy_type $(,#[$meta])*);
    };
    ($ty:ty $(,#[$meta:meta])*) => {
        impl_element_scalar!(@impl: $ty, npy_int_type::<$ty>() $(,#[$meta])*);
    };
}

impl_element_scalar!(bool, NPY_BOOL);
impl_element_scalar!(i8);
impl_element_scalar!(i16);
impl_element_scalar!(i32);
impl_element_scalar!(i64);
impl_element_scalar!(u8);
impl_element_scalar!(u16);
impl_element_scalar!(u32);
impl_element_scalar!(u64);
impl_element_scalar!(f32, NPY_FLOAT);
impl_element_scalar!(f64, NPY_DOUBLE);
impl_element_scalar!(Complex32, NPY_CFLOAT,
    #[doc = "Complex type with `f32` components which maps to `np.csingle` (`np.complex64`)."]);
impl_element_scalar!(Complex64, NPY_CDOUBLE,
    #[doc = "Complex type with `f64` components which maps to `np.cdouble` (`np.complex128`)."]);

cfg_if! {
    if #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] {
        impl_element_scalar!(usize);
        impl_element_scalar!(isize);
    }
}

unsafe impl Element for PyObject {
    const IS_COPY: bool = false;

    fn get_dtype(py: Python) -> &PyArrayDescr {
        PyArrayDescr::object(py)
    }
}

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

    use super::{Complex32, Complex64, Element, PyArrayDescr};

    #[test]
    fn test_dtype_names() {
        fn type_name<T: Element>(py: pyo3::Python) -> &str {
            PyArrayDescr::of::<T>(py).get_type().name().unwrap()
        }
        pyo3::Python::with_gil(|py| {
            assert_eq!(type_name::<bool>(py), "bool_");
            assert_eq!(type_name::<i8>(py), "int8");
            assert_eq!(type_name::<i16>(py), "int16");
            assert_eq!(type_name::<i32>(py), "int32");
            assert_eq!(type_name::<i64>(py), "int64");
            assert_eq!(type_name::<u8>(py), "uint8");
            assert_eq!(type_name::<u16>(py), "uint16");
            assert_eq!(type_name::<u32>(py), "uint32");
            assert_eq!(type_name::<u64>(py), "uint64");
            assert_eq!(type_name::<f32>(py), "float32");
            assert_eq!(type_name::<f64>(py), "float64");
            assert_eq!(type_name::<Complex32>(py), "complex64");
            assert_eq!(type_name::<Complex64>(py), "complex128");
            match size_of::<usize>() {
                32 => {
                    assert_eq!(type_name::<usize>(py), "uint32");
                    assert_eq!(type_name::<isize>(py), "int32");
                }
                64 => {
                    assert_eq!(type_name::<usize>(py), "uint64");
                    assert_eq!(type_name::<isize>(py), "int64");
                }
                _ => {}
            }
        });
    }
}
<commit_msg>Update the docstring for `Element`<commit_after>use std::mem::size_of;
use std::os::raw::{c_int, c_long, c_longlong, c_short, c_uint, c_ulong, c_ulonglong, c_ushort};

use cfg_if::cfg_if;
use num_traits::{Bounded, Zero};
use pyo3::{ffi, prelude::*, pyobject_native_type_core, types::PyType, AsPyPointer, PyNativeType};

use crate::npyffi::{NpyTypes, PyArray_Descr, NPY_TYPES, PY_ARRAY_API};

pub use num_complex::{Complex32, Complex64};

/// Binding of [`numpy.dtype`](https://numpy.org/doc/stable/reference/generated/numpy.dtype.html).
///
/// # Example
/// ```
/// use pyo3::types::IntoPyDict;
/// pyo3::Python::with_gil(|py| {
///     let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
///     let dtype: &numpy::PyArrayDescr = py
///         .eval("np.array([1, 2, 3.0]).dtype", Some(locals), None)
///         .unwrap()
///         .downcast()
///         .unwrap();
///     assert!(dtype.is_equiv_to(numpy::PyArrayDescr::of::<f64>(py)));
/// });
/// ```
pub struct PyArrayDescr(PyAny);

pyobject_native_type_core!(
    PyArrayDescr,
    *PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    #module=Some("numpy"),
    #checkfunction=arraydescr_check
);

unsafe fn arraydescr_check(op: *mut ffi::PyObject) -> c_int {
    ffi::PyObject_TypeCheck(
        op,
        PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    )
}

impl PyArrayDescr {
    /// Returns `self` as `*mut PyArray_Descr`.
    pub fn as_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.as_ptr() as _
    }

    /// Returns `self` as `*mut PyArray_Descr` while increasing the reference count.
    ///
    /// Useful in cases where the descriptor is stolen by the API.
    pub fn into_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.into_ptr() as _
    }

    /// Returns the internal `PyType` that this `dtype` holds.
    ///
    /// # Example
    /// ```
    /// pyo3::Python::with_gil(|py| {
    ///    let array = numpy::PyArray::from_vec(py, vec![0.0, 1.0, 2.0f64]);
    ///    let dtype = array.dtype();
    ///    assert_eq!(dtype.get_type().name().unwrap().to_string(), "float64");
    /// });
    /// ```
    pub fn get_type(&self) -> &PyType {
        let dtype_type_ptr = unsafe { *self.as_dtype_ptr() }.typeobj;
        unsafe { PyType::from_type_ptr(self.py(), dtype_type_ptr) }
    }

    /// Shortcut for creating a descriptor of 'object' type.
    pub fn object(py: Python) -> &Self {
        Self::from_npy_type(py, NPY_TYPES::NPY_OBJECT)
    }

    /// Returns the type descriptor for a registered type.
    pub fn of<T: Element>(py: Python) -> &Self {
        T::get_dtype(py)
    }

    /// Returns true if two type descriptors are equivalent.
    pub fn is_equiv_to(&self, other: &Self) -> bool {
        unsafe { PY_ARRAY_API.PyArray_EquivTypes(self.as_dtype_ptr(), other.as_dtype_ptr()) != 0 }
    }

    fn from_npy_type(py: Python, npy_type: NPY_TYPES) -> &Self {
        unsafe {
            let descr = PY_ARRAY_API.PyArray_DescrFromType(npy_type as _);
            py.from_owned_ptr(descr as _)
        }
    }

    /// Retrieves the
    /// [enumerated type](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
    /// for this type descriptor.
    pub fn get_typenum(&self) -> c_int {
        unsafe { *self.as_dtype_ptr() }.type_num
    }
}

/// Represents that a type can be an element of `PyArray`.
///
/// Currently, only integer/float/complex types are supported.
/// If you come up with a nice implementation for some other types, we're happy to receive your PR :)
/// You may refer to the [numpy document](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
/// for all types that numpy supports.
///
/// # Safety
///
/// A type `T` that implements this trait should be safe when managed in numpy
/// array, thus implementing this trait is marked unsafe. Data types that don't
/// contain Python objects (i.e., either the object type itself or record types
/// containing object-type fields) are assumed to be trivially copyable, which
/// is reflected in the `IS_COPY` flag. Furthermore, it is assumed that for
/// the object type the elements are pointers into the Python heap and that the
/// corresponding `Clone` implemenation will never panic as it only increases
/// the reference count.
///
/// # Custom element types
///
/// You can implement this trait to manage arrays of custom element types, but they still need to be stored
/// on Python's heap using PyO3's [Py](pyo3::Py) type.
///
/// ```
/// use numpy::{ndarray::Array2, Element, PyArray, PyArrayDescr, ToPyArray};
/// use pyo3::{pyclass, Py, Python};
///
/// #[pyclass]
/// pub struct CustomElement;
///
/// // The transparent wrapper is necessary as one cannot implement
/// // a foreign trait (`Element`) on a foreign type (`Py`) directly.
/// #[derive(Clone)]
/// #[repr(transparent)]
/// pub struct Wrapper(pub Py<CustomElement>);
///
/// unsafe impl Element for Wrapper {
///     const IS_COPY: bool = false;
///
///     fn get_dtype(py: Python) -> &PyArrayDescr {
///         PyArrayDescr::object(py)
///     }
/// }
///
/// Python::with_gil(|py| {
///     let array = Array2::<Wrapper>::from_shape_fn((2, 3), |(_i, _j)| {
///         Wrapper(Py::new(py, CustomElement).unwrap())
///     });
///
///     let _array: &PyArray<Wrapper, _> = array.to_pyarray(py);
/// });
/// ```
pub unsafe trait Element: Clone + Send {
    /// Flag that indicates whether this type is trivially copyable.
    ///
    /// It should be set to true for all trivially copyable types (like scalar types
    /// and record/array types only containing trivially copyable fields and elements).
    ///
    /// This flag should *always* be set to `false` for object types or record types
    /// that contain object-type fields.
    const IS_COPY: bool;

    /// Returns the associated array descriptor ("dtype") for the given type.
    fn get_dtype(py: Python) -> &PyArrayDescr;
}

fn npy_int_type_lookup<T, T0, T1, T2>(npy_types: [NPY_TYPES; 3]) -> NPY_TYPES {
    // `npy_common.h` defines the integer aliases. In order, it checks:
    // NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR
    // and assigns the alias to the first matching size, so we should check in this order.
    match size_of::<T>() {
        x if x == size_of::<T0>() => npy_types[0],
        x if x == size_of::<T1>() => npy_types[1],
        x if x == size_of::<T2>() => npy_types[2],
        _ => panic!("Unable to match integer type descriptor: {:?}", npy_types),
    }
}

fn npy_int_type<T: Bounded + Zero + Sized + PartialEq>() -> NPY_TYPES {
    let is_unsigned = T::min_value() == T::zero();
    let bit_width = size_of::<T>() << 3;

    match (is_unsigned, bit_width) {
        (false, 8) => NPY_TYPES::NPY_BYTE,
        (false, 16) => NPY_TYPES::NPY_SHORT,
        (false, 32) => npy_int_type_lookup::<i32, c_long, c_int, c_short>([
            NPY_TYPES::NPY_LONG,
            NPY_TYPES::NPY_INT,
            NPY_TYPES::NPY_SHORT,
        ]),
        (false, 64) => npy_int_type_lookup::<i64, c_long, c_longlong, c_int>([
            NPY_TYPES::NPY_LONG,
            NPY_TYPES::NPY_LONGLONG,
            NPY_TYPES::NPY_INT,
        ]),
        (true, 8) => NPY_TYPES::NPY_UBYTE,
        (true, 16) => NPY_TYPES::NPY_USHORT,
        (true, 32) => npy_int_type_lookup::<u32, c_ulong, c_uint, c_ushort>([
            NPY_TYPES::NPY_ULONG,
            NPY_TYPES::NPY_UINT,
            NPY_TYPES::NPY_USHORT,
        ]),
        (true, 64) => npy_int_type_lookup::<u64, c_ulong, c_ulonglong, c_uint>([
            NPY_TYPES::NPY_ULONG,
            NPY_TYPES::NPY_ULONGLONG,
            NPY_TYPES::NPY_UINT,
        ]),
        _ => unreachable!(),
    }
}

macro_rules! impl_element_scalar {
    (@impl: $ty:ty, $npy_type:expr $(,#[$meta:meta])*) => {
        $(#[$meta])*
        unsafe impl Element for $ty {
            const IS_COPY: bool = true;
            fn get_dtype(py: Python) -> &PyArrayDescr {
                PyArrayDescr::from_npy_type(py, $npy_type)
            }
        }
    };
    ($ty:ty, $npy_type:ident $(,#[$meta:meta])*) => {
        impl_element_scalar!(@impl: $ty, NPY_TYPES::$npy_type $(,#[$meta])*);
    };
    ($ty:ty $(,#[$meta:meta])*) => {
        impl_element_scalar!(@impl: $ty, npy_int_type::<$ty>() $(,#[$meta])*);
    };
}

impl_element_scalar!(bool, NPY_BOOL);
impl_element_scalar!(i8);
impl_element_scalar!(i16);
impl_element_scalar!(i32);
impl_element_scalar!(i64);
impl_element_scalar!(u8);
impl_element_scalar!(u16);
impl_element_scalar!(u32);
impl_element_scalar!(u64);
impl_element_scalar!(f32, NPY_FLOAT);
impl_element_scalar!(f64, NPY_DOUBLE);
impl_element_scalar!(Complex32, NPY_CFLOAT,
    #[doc = "Complex type with `f32` components which maps to `np.csingle` (`np.complex64`)."]);
impl_element_scalar!(Complex64, NPY_CDOUBLE,
    #[doc = "Complex type with `f64` components which maps to `np.cdouble` (`np.complex128`)."]);

cfg_if! {
    if #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] {
        impl_element_scalar!(usize);
        impl_element_scalar!(isize);
    }
}

unsafe impl Element for PyObject {
    const IS_COPY: bool = false;

    fn get_dtype(py: Python) -> &PyArrayDescr {
        PyArrayDescr::object(py)
    }
}

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

    use super::{Complex32, Complex64, Element, PyArrayDescr};

    #[test]
    fn test_dtype_names() {
        fn type_name<T: Element>(py: pyo3::Python) -> &str {
            PyArrayDescr::of::<T>(py).get_type().name().unwrap()
        }
        pyo3::Python::with_gil(|py| {
            assert_eq!(type_name::<bool>(py), "bool_");
            assert_eq!(type_name::<i8>(py), "int8");
            assert_eq!(type_name::<i16>(py), "int16");
            assert_eq!(type_name::<i32>(py), "int32");
            assert_eq!(type_name::<i64>(py), "int64");
            assert_eq!(type_name::<u8>(py), "uint8");
            assert_eq!(type_name::<u16>(py), "uint16");
            assert_eq!(type_name::<u32>(py), "uint32");
            assert_eq!(type_name::<u64>(py), "uint64");
            assert_eq!(type_name::<f32>(py), "float32");
            assert_eq!(type_name::<f64>(py), "float64");
            assert_eq!(type_name::<Complex32>(py), "complex64");
            assert_eq!(type_name::<Complex64>(py), "complex128");
            match size_of::<usize>() {
                32 => {
                    assert_eq!(type_name::<usize>(py), "uint32");
                    assert_eq!(type_name::<isize>(py), "int32");
                }
                64 => {
                    assert_eq!(type_name::<usize>(py), "uint64");
                    assert_eq!(type_name::<isize>(py), "int64");
                }
                _ => {}
            }
        });
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

/// Enumeration of possible errors thrown
/// within the statrs library
pub enum StatsError {
    BadParams,
    ArgMustBePositive(&'static str),
    ArgNotNegative(&'static str),
    ArgIntervalIncl(&'static str, f64, f64),
    ArgIntervalExcl(&'static str, f64, f64),
    ArgIntervalExclMin(&'static str, f64, f64),
    ArgIntervalExclMax(&'static str, f64, f64),
}

impl Error for StatsError {
    fn description(&self) -> &str {
        "Error performing statistical calculation"
    }
}

impl fmt::Display for StatsError{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StatsError::BadParams => write!(f, "Bad distribution parameters"),
            StatsError::ArgMustBePositive(s) => write!(f, "Argument {} must be positive", s),
            StatsError::ArgNotNegative(s) => write!(f, "Argument {} must be non-negative", s),
            StatsError::ArgIntervalIncl(s, min, max) => write!(f, "Argument {} not within interval [{}, {}]", s, min, max),
            StatsError::ArgIntervalExcl(s, min, max) => write!(f, "Argument {} not within interval ({}, {})", s, min, max),
            StatsError::ArgIntervalExclMin(s, min, max) => write!(f, "Argument {} not within interval ({}, {}]", s, min, max),
            StatsError::ArgIntervalExclMax(s, min, max) => write!(f, "Argument {} not within interval [{}, {})", s, min, max),
        }
    }
}

impl fmt::Debug for StatsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StatsError::BadParams => write!(f, "Bad distribution parameters"),
            StatsError::ArgMustBePositive(s) => write!(f, "Argument {} must be positive", s),
            StatsError::ArgNotNegative(s) => write!(f, "Argument {} must be non-negative", s),
            StatsError::ArgIntervalIncl(s, min, max) => write!(f, "Argument {} not within interval [{}, {}]", s, min, max),
            StatsError::ArgIntervalExcl(s, min, max) => write!(f, "Argument {} not within interval ({}, {})", s, min, max),
            StatsError::ArgIntervalExclMin(s, min, max) => write!(f, "Argument {} not within interval ({}, {}]", s, min, max),
            StatsError::ArgIntervalExclMax(s, min, max) => write!(f, "Argument {} not within interval [{}, {})", s, min, max),
        }
    }
}<commit_msg>make StatsError Debug trait derived<commit_after>use std::error::Error;
use std::fmt;

/// Enumeration of possible errors thrown
/// within the statrs library
#[derive(Debug)]
pub enum StatsError {
    BadParams,
    ArgMustBePositive(&'static str),
    ArgNotNegative(&'static str),
    ArgIntervalIncl(&'static str, f64, f64),
    ArgIntervalExcl(&'static str, f64, f64),
    ArgIntervalExclMin(&'static str, f64, f64),
    ArgIntervalExclMax(&'static str, f64, f64),
}

impl Error for StatsError {
    fn description(&self) -> &str {
        "Error performing statistical calculation"
    }
}

impl fmt::Display for StatsError{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StatsError::BadParams => write!(f, "Bad distribution parameters"),
            StatsError::ArgMustBePositive(s) => write!(f, "Argument {} must be positive", s),
            StatsError::ArgNotNegative(s) => write!(f, "Argument {} must be non-negative", s),
            StatsError::ArgIntervalIncl(s, min, max) => write!(f, "Argument {} not within interval [{}, {}]", s, min, max),
            StatsError::ArgIntervalExcl(s, min, max) => write!(f, "Argument {} not within interval ({}, {})", s, min, max),
            StatsError::ArgIntervalExclMin(s, min, max) => write!(f, "Argument {} not within interval ({}, {}]", s, min, max),
            StatsError::ArgIntervalExclMax(s, min, max) => write!(f, "Argument {} not within interval [{}, {})", s, min, max),
        }
    }
}<|endoftext|>


<commit_before>//! Error types
use std::{fmt, str};
use std::fmt::Display;
use ::json;
use reqwest;

error_chain! {
    errors {
        /// Error from the Algorithmia API (may be from the algorithm)
        Api(err: ApiError) {
            description("api error")
            display("api error - {}", err)
        }

        /// Http errors calling the API
        Http(context: String) {
            description("http error")
            display("http error {}", context)
        }

        /// Base URL couldn't be parsed as a `Url`
        InvalidBaseUrl {
            description("invalid base url")
        }

        /// Invalid Data URI
        InvalidDataUri(uri: String) {
            description("invalid data uri")
            display("invalid url uri '{}'", uri)
        }

        /// Invalid Algorithm URI
        InvalidAlgoUri(uri: String) {
            description("invalid algorithm uri")
            display("invalid algorithm uri: {}", &uri)
        }

        /// Error decoding JSON
        DecodeJson(item: &'static str) {
            description("json decode error")
            display("failed to decode {} json", item)
        }

        /// Error encoding JSON
        EncodeJson(item: &'static str) {
            description("json encode error")
            display("failed to encode {} as json", item)
        }

        /// Error decoding base64
        DecodeBase64(item: &'static str) {
            description("base64 error")
            display("failed to decode {} as base64", item)
        }

        /// I/O errors reading or writing data
        Io(context: String) {
            description("io error")
            display("io error {}", context)
        }

        /// API responded with unknown content type
        InvalidContentType(t: String) {
            description("invalid content type")
            display("invalid content type: '{}'", t)
        }

        /// Content was not valid for the specified content-type
        MismatchedContentType(expected: &'static str) {
            description("mismatched content type")
            display("content did not match content type: '{}'", expected)
        }

        /// Content type is not the expected content type
        UnexpectedContentType(expected: &'static str, actual: String) {
            description("unexpected content type")
            display("expected content type '{}', received '{}'", expected, actual)
        }

        /// Encountered 404 Not Found
        NotFound(url: reqwest::Url) {
            description("404 not found")
            display("404 not found: {}", url)
        }

        /// API response was missing a data type header
        MissingDataType {
            description("api response missing data type")
        }

        /// API response included an unknown data type header
        InvalidDataType(t: String) {
            description("invalid data type")
            display("api responded with invalid data type: '{}'", t)
        }

        /// API response included an unexpected data type header
        UnexpectedDataType(expected: &'static str, actual: String) {
            description("unexpected data type")
            display("expected api response with data type '{}', received '{}'", expected, actual)
        }

        /// Entrypoint not defined for input type
        UnsupportedInput {
            description("unsupported input type")
        }

        #[doc(hidden)]
        __DontMatchMe {}
    }
}

/// Error from the Algorithmia API (may be from the algorithm)
#[cfg_attr(feature="with-serde", derive(Deserialize))]
#[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable))]
#[derive(Debug)]
pub struct ApiError {
    /// Error message returned from the Algorithmia API
    pub message: String,
    /// Stacktrace of algorithm exception/panic
    pub stacktrace: Option<String>,
}

impl Display for ApiError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.stacktrace {
            Some(ref trace) => write!(f, "{}\n{}", self.message, trace),
            None => write!(f, "{}", self.message),
        }
    }
}

/// Struct for decoding Algorithmia API error responses
#[cfg_attr(feature="with-serde", derive(Deserialize))]
#[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable))]
#[derive(Debug)]
#[doc(hidden)]
pub struct ApiErrorResponse {
    pub error: ApiError,
}

/// Helper to decode API responses into errors
pub fn decode(json_str: &str) -> Error {
    let decoded_error = json::decode_str::<ApiErrorResponse>(json_str);
    match decoded_error.chain_err(|| ErrorKind::DecodeJson("api error response")) {
        Ok(err_res) => ErrorKind::Api(err_res.error).into(),
        Err(err) => err,
    }
}
<commit_msg>Fix error message<commit_after>//! Error types
use std::{fmt, str};
use std::fmt::Display;
use ::json;
use reqwest;

error_chain! {
    errors {
        /// Error from the Algorithmia API (may be from the algorithm)
        Api(err: ApiError) {
            description("api error")
            display("api error - {}", err)
        }

        /// Http errors calling the API
        Http(context: String) {
            description("http error")
            display("http error {}", context)
        }

        /// Base URL couldn't be parsed as a `Url`
        InvalidBaseUrl {
            description("invalid base url")
        }

        /// Invalid Data URI
        InvalidDataUri(uri: String) {
            description("invalid data uri")
            display("invalid data uri '{}'", uri)
        }

        /// Invalid Algorithm URI
        InvalidAlgoUri(uri: String) {
            description("invalid algorithm uri")
            display("invalid algorithm uri: {}", &uri)
        }

        /// Error decoding JSON
        DecodeJson(item: &'static str) {
            description("json decode error")
            display("failed to decode {} json", item)
        }

        /// Error encoding JSON
        EncodeJson(item: &'static str) {
            description("json encode error")
            display("failed to encode {} as json", item)
        }

        /// Error decoding base64
        DecodeBase64(item: &'static str) {
            description("base64 error")
            display("failed to decode {} as base64", item)
        }

        /// I/O errors reading or writing data
        Io(context: String) {
            description("io error")
            display("io error {}", context)
        }

        /// API responded with unknown content type
        InvalidContentType(t: String) {
            description("invalid content type")
            display("invalid content type: '{}'", t)
        }

        /// Content was not valid for the specified content-type
        MismatchedContentType(expected: &'static str) {
            description("mismatched content type")
            display("content did not match content type: '{}'", expected)
        }

        /// Content type is not the expected content type
        UnexpectedContentType(expected: &'static str, actual: String) {
            description("unexpected content type")
            display("expected content type '{}', received '{}'", expected, actual)
        }

        /// Encountered 404 Not Found
        NotFound(url: reqwest::Url) {
            description("404 not found")
            display("404 not found: {}", url)
        }

        /// API response was missing a data type header
        MissingDataType {
            description("api response missing data type")
        }

        /// API response included an unknown data type header
        InvalidDataType(t: String) {
            description("invalid data type")
            display("api responded with invalid data type: '{}'", t)
        }

        /// API response included an unexpected data type header
        UnexpectedDataType(expected: &'static str, actual: String) {
            description("unexpected data type")
            display("expected api response with data type '{}', received '{}'", expected, actual)
        }

        /// Entrypoint not defined for input type
        UnsupportedInput {
            description("unsupported input type")
        }

        #[doc(hidden)]
        __DontMatchMe {}
    }
}

/// Error from the Algorithmia API (may be from the algorithm)
#[cfg_attr(feature="with-serde", derive(Deserialize))]
#[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable))]
#[derive(Debug)]
pub struct ApiError {
    /// Error message returned from the Algorithmia API
    pub message: String,
    /// Stacktrace of algorithm exception/panic
    pub stacktrace: Option<String>,
}

impl Display for ApiError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.stacktrace {
            Some(ref trace) => write!(f, "{}\n{}", self.message, trace),
            None => write!(f, "{}", self.message),
        }
    }
}

/// Struct for decoding Algorithmia API error responses
#[cfg_attr(feature="with-serde", derive(Deserialize))]
#[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable))]
#[derive(Debug)]
#[doc(hidden)]
pub struct ApiErrorResponse {
    pub error: ApiError,
}

/// Helper to decode API responses into errors
pub fn decode(json_str: &str) -> Error {
    let decoded_error = json::decode_str::<ApiErrorResponse>(json_str);
    match decoded_error.chain_err(|| ErrorKind::DecodeJson("api error response")) {
        Ok(err_res) => ErrorKind::Api(err_res.error).into(),
        Err(err) => err,
    }
}
<|endoftext|>


<commit_before>extern crate envy;
extern crate getopts;
extern crate reqwest;
extern crate url;

use std::ffi::OsString;
use std::fmt;
use std::io;
use std::path::PathBuf;

#[derive(Debug)]
pub enum ExpectedNumberOfArgs {
    Single(usize),
    Range(usize, usize),
}

impl fmt::Display for ExpectedNumberOfArgs {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ExpectedNumberOfArgs::Single(num) => write!(f, "{}", num),
            ExpectedNumberOfArgs::Range(min, max) => write!(f, "{}..{}", min, max),
        }
    }
}

#[derive(Debug)]
pub enum Error {
    BrokenRepoFormat {
        input: String,
    },
    CliParseFail(getopts::Fail),
    OpenUrlFailure {
        url: String,
        msg: String,
    },
    GitLabDiffNotSupported,
    BitbucketDiffNotSupported,
    NoUserInPath {
        path: String,
    },
    NoRepoInPath {
        path: String,
    },
    UnknownHostingService {
        url: String,
    },
    GitHubPullReqNotFound {
        author: String,
        repo: String,
        branch: String,
    },
    BrokenUrl {
        url: String,
        msg: String,
    },
    PullReqNotSupported {
        service: String,
    },
    GitHubStatusFailure {
        status: reqwest::StatusCode,
        msg: String,
    },
    HttpClientError(reqwest::Error),
    IoError(io::Error),
    GitCommandError {
        stderr: String,
        args: Vec<OsString>,
    },
    UnexpectedRemoteName(String),
    GitObjectNotFound {
        kind: &'static str,
        object: String,
        msg: String,
    },
    GitRootDirNotFound {
        git_dir: PathBuf,
    },
    WrongNumberOfArgs {
        expected: ExpectedNumberOfArgs,
        actual: usize,
        kind: String,
    },
    DiffDotsNotFound,
    DiffHandIsEmpty {
        input: String,
    },
    FileDirNotInRepo {
        repo_root: PathBuf,
        path: PathBuf,
    },
    PageParseError {
        args: Vec<String>,
        attempts: Vec<Error>,
    },
    InvalidIssueNumberFormat,
    LineSpecifiedForDir(PathBuf),
    EnvLoadError(envy::Error),
    NoLocalRepoFound {
        operation: String,
    },
    NoSearchResult {
        query: String,
    },
    ArgsNotAllowed {
        flag: &'static str,
        args: Vec<String>,
    },
    GheTokenRequired,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BrokenRepoFormat {input} => write!(f, "Invalid repository format '{}' or unknown remote. Note: Format must be one of 'repo', 'user/repo', 'host/user/repo', Git URL", input),
            Error::CliParseFail(e) => write!(f, "{}", e),
            Error::OpenUrlFailure {url, msg} => write!(f, "{}: Cannot open URL {}", msg, url),
            Error::GitLabDiffNotSupported => write!(f, "GitLab does not support '..' for comparing diff between commits. Please use '...'"),
            Error::BitbucketDiffNotSupported => write!(f, "BitBucket does not support diff between commits (see https://bitbucket.org/site/master/issues/4779/ability-to-diff-between-any-two-commits)"),
            Error::NoUserInPath{path} => write!(f, "Can't detect user name from path {}", path),
            Error::NoRepoInPath{path} => write!(f, "Can't detect repository name from path {}", path),
            Error::UnknownHostingService {url} => write!(f, "Unknown hosting service for URL {}. If you want to use custom URL for GitHub Enterprise, please set $GIT_BRWS_GHE_URL_HOST", url),
            Error::GitHubPullReqNotFound{author, repo, branch} => write!(f, "No pull request authored by @{} at {}@{}", author, repo, branch),
            Error::BrokenUrl {url, msg} => write!(f, "Broken URL '{}': {}", url, msg),
            Error::PullReqNotSupported {service} => write!(f, "--pr or -p does not support the service {}", service),
            Error::GitHubStatusFailure {status, msg} => write!(f, "GitHub API response status {}: {}", status, msg),
            Error::HttpClientError(err) => write!(f, "{}", err),
            Error::IoError(err) => write!(f, "{}", err),
            Error::GitCommandError{stderr, args} => {
                if stderr.is_empty() {
                    write!(f, "`git")?;
                } else {
                    write!(f, "{}: `git", stderr)?;
                }
                for arg in args.iter() {
                    write!(f, " '{}'", arg.to_string_lossy())?;
                }
                write!(f, "` exited with non-zero status")
            }
            Error::GitObjectNotFound{kind, object, msg} if msg.is_empty() => write!(f, "Git could not find {} '{}'", kind, object),
            Error::GitObjectNotFound{kind, object, msg} => write!(f, "Git could not find {} '{}': {}", kind, object, msg),
            Error::GitRootDirNotFound{git_dir} => write!(f, "Cannot locate root directory from GIT_DIR {:?}", git_dir),
            Error::UnexpectedRemoteName(name) => write!(f, "Tracking name must be remote-url/branch-name: {}", name),
            Error::WrongNumberOfArgs{expected, actual, kind} => write!(f, "Invalid number of arguments for {}. {} is expected but given {}", kind, expected, actual),
            Error::DiffDotsNotFound => write!(f, "'..' or '...' must be contained for diff"),
            Error::DiffHandIsEmpty{input} => write!(f, "Not a diff format since LHS and/or RHS is empty {}", input),
            Error::FileDirNotInRepo{repo_root, path} => write!(f, "Given path '{:?}' is not in repository '{:?}'", path, repo_root),
            Error::PageParseError{args, attempts} => {
                write!(f, "Error on parsing command line arguments {:?}", args)?;
                for err in attempts.iter() {
                    write!(f, "\n  - {}", err)?;
                }
                Ok(())
            }
            Error::InvalidIssueNumberFormat => write!(f, "Issue number must start with '#' followed by numbers like #123"),
            Error::LineSpecifiedForDir(path) => write!(f, "Directory cannot have line number: {:?}", path),
            Error::EnvLoadError(err) => write!(f, "Cannot load environment variable: {}", err),
            Error::NoLocalRepoFound{operation} => write!(f, ".git directory was not found. For {}, local repository must be known", operation),
            Error::NoSearchResult{query} => write!(f, "No repository was hit for query '{}'", query),
            Error::ArgsNotAllowed{flag, args} => write!(f, "{} option does not allow any command line argument. It opens page based on {{repo}}, but argument(s) {:?} retrives information from local directory.", flag, args),
            Error::GheTokenRequired => write!(f, "GitHub Enterprise requires API token. Please set $GIT_BRWS_GHE_TOKEN"),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<reqwest::Error> for Error {
    fn from(inner: reqwest::Error) -> Error {
        Error::HttpClientError(inner)
    }
}

impl From<getopts::Fail> for Error {
    fn from(f: getopts::Fail) -> Error {
        Error::CliParseFail(f)
    }
}

impl From<envy::Error> for Error {
    fn from(e: envy::Error) -> Error {
        Error::EnvLoadError(e)
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;
<commit_msg>improve error message when git command does not exist<commit_after>extern crate envy;
extern crate getopts;
extern crate reqwest;
extern crate url;

use std::ffi::OsString;
use std::fmt;
use std::io;
use std::path::PathBuf;

#[derive(Debug)]
pub enum ExpectedNumberOfArgs {
    Single(usize),
    Range(usize, usize),
}

impl fmt::Display for ExpectedNumberOfArgs {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ExpectedNumberOfArgs::Single(num) => write!(f, "{}", num),
            ExpectedNumberOfArgs::Range(min, max) => write!(f, "{}..{}", min, max),
        }
    }
}

#[derive(Debug)]
pub enum Error {
    BrokenRepoFormat {
        input: String,
    },
    CliParseFail(getopts::Fail),
    OpenUrlFailure {
        url: String,
        msg: String,
    },
    GitLabDiffNotSupported,
    BitbucketDiffNotSupported,
    NoUserInPath {
        path: String,
    },
    NoRepoInPath {
        path: String,
    },
    UnknownHostingService {
        url: String,
    },
    GitHubPullReqNotFound {
        author: String,
        repo: String,
        branch: String,
    },
    BrokenUrl {
        url: String,
        msg: String,
    },
    PullReqNotSupported {
        service: String,
    },
    GitHubStatusFailure {
        status: reqwest::StatusCode,
        msg: String,
    },
    HttpClientError(reqwest::Error),
    IoError(io::Error),
    GitCommandError {
        stderr: String,
        args: Vec<OsString>,
    },
    UnexpectedRemoteName(String),
    GitObjectNotFound {
        kind: &'static str,
        object: String,
        msg: String,
    },
    GitRootDirNotFound {
        git_dir: PathBuf,
    },
    WrongNumberOfArgs {
        expected: ExpectedNumberOfArgs,
        actual: usize,
        kind: String,
    },
    DiffDotsNotFound,
    DiffHandIsEmpty {
        input: String,
    },
    FileDirNotInRepo {
        repo_root: PathBuf,
        path: PathBuf,
    },
    PageParseError {
        args: Vec<String>,
        attempts: Vec<Error>,
    },
    InvalidIssueNumberFormat,
    LineSpecifiedForDir(PathBuf),
    EnvLoadError(envy::Error),
    NoLocalRepoFound {
        operation: String,
    },
    NoSearchResult {
        query: String,
    },
    ArgsNotAllowed {
        flag: &'static str,
        args: Vec<String>,
    },
    GheTokenRequired,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BrokenRepoFormat {input} => write!(f, "Invalid repository format '{}' or unknown remote. Note: Format must be one of 'repo', 'user/repo', 'host/user/repo', Git URL", input),
            Error::CliParseFail(e) => write!(f, "{}", e),
            Error::OpenUrlFailure {url, msg} => write!(f, "{}: Cannot open URL {}", msg, url),
            Error::GitLabDiffNotSupported => write!(f, "GitLab does not support '..' for comparing diff between commits. Please use '...'"),
            Error::BitbucketDiffNotSupported => write!(f, "BitBucket does not support diff between commits (see https://bitbucket.org/site/master/issues/4779/ability-to-diff-between-any-two-commits)"),
            Error::NoUserInPath{path} => write!(f, "Can't detect user name from path {}", path),
            Error::NoRepoInPath{path} => write!(f, "Can't detect repository name from path {}", path),
            Error::UnknownHostingService {url} => write!(f, "Unknown hosting service for URL {}. If you want to use custom URL for GitHub Enterprise, please set $GIT_BRWS_GHE_URL_HOST", url),
            Error::GitHubPullReqNotFound{author, repo, branch} => write!(f, "No pull request authored by @{} at {}@{}", author, repo, branch),
            Error::BrokenUrl {url, msg} => write!(f, "Broken URL '{}': {}", url, msg),
            Error::PullReqNotSupported {service} => write!(f, "--pr or -p does not support the service {}", service),
            Error::GitHubStatusFailure {status, msg} => write!(f, "GitHub API response status {}: {}", status, msg),
            Error::HttpClientError(err) => write!(f, "{}", err),
            Error::IoError(err) => write!(f, "I/O error: {}. Note: Git command or current directory or file path may not exist", err),
            Error::GitCommandError{stderr, args} => {
                if stderr.is_empty() {
                    write!(f, "`git")?;
                } else {
                    write!(f, "{}: `git", stderr)?;
                }
                for arg in args.iter() {
                    write!(f, " '{}'", arg.to_string_lossy())?;
                }
                write!(f, "` exited with non-zero status")
            }
            Error::GitObjectNotFound{kind, object, msg} if msg.is_empty() => write!(f, "Git could not find {} '{}'", kind, object),
            Error::GitObjectNotFound{kind, object, msg} => write!(f, "Git could not find {} '{}': {}", kind, object, msg),
            Error::GitRootDirNotFound{git_dir} => write!(f, "Cannot locate root directory from GIT_DIR {:?}", git_dir),
            Error::UnexpectedRemoteName(name) => write!(f, "Tracking name must be remote-url/branch-name: {}", name),
            Error::WrongNumberOfArgs{expected, actual, kind} => write!(f, "Invalid number of arguments for {}. {} is expected but given {}", kind, expected, actual),
            Error::DiffDotsNotFound => write!(f, "'..' or '...' must be contained for diff"),
            Error::DiffHandIsEmpty{input} => write!(f, "Not a diff format since LHS and/or RHS is empty {}", input),
            Error::FileDirNotInRepo{repo_root, path} => write!(f, "Given path '{:?}' is not in repository '{:?}'", path, repo_root),
            Error::PageParseError{args, attempts} => {
                write!(f, "Error on parsing command line arguments {:?}", args)?;
                for err in attempts.iter() {
                    write!(f, "\n  - {}", err)?;
                }
                Ok(())
            }
            Error::InvalidIssueNumberFormat => write!(f, "Issue number must start with '#' followed by numbers like #123"),
            Error::LineSpecifiedForDir(path) => write!(f, "Directory cannot have line number: {:?}", path),
            Error::EnvLoadError(err) => write!(f, "Cannot load environment variable: {}", err),
            Error::NoLocalRepoFound{operation} => write!(f, ".git directory was not found. For {}, local repository must be known", operation),
            Error::NoSearchResult{query} => write!(f, "No repository was hit for query '{}'", query),
            Error::ArgsNotAllowed{flag, args} => write!(f, "{} option does not allow any command line argument. It opens page based on {{repo}}, but argument(s) {:?} retrives information from local directory.", flag, args),
            Error::GheTokenRequired => write!(f, "GitHub Enterprise requires API token. Please set $GIT_BRWS_GHE_TOKEN"),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<reqwest::Error> for Error {
    fn from(inner: reqwest::Error) -> Error {
        Error::HttpClientError(inner)
    }
}

impl From<getopts::Fail> for Error {
    fn from(f: getopts::Fail) -> Error {
        Error::CliParseFail(f)
    }
}

impl From<envy::Error> for Error {
    fn from(e: envy::Error) -> Error {
        Error::EnvLoadError(e)
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;
<|endoftext|>


<commit_before>use serde_json::Error as JsonError;
use std::io::Error as IoError;
use std::error::Error as StdError;
use std::fmt::{self, Display, Error as FormatError};
use std::num::ParseIntError;
use internal::prelude::*;
use model::ModelError;

#[cfg(feature = "hyper")]
use hyper::Error as HyperError;
#[cfg(feature = "native-tls")]
use native_tls::Error as TlsError;
#[cfg(feature = "voice")]
use opus::Error as OpusError;
#[cfg(feature = "websocket")]
use websocket::result::WebSocketError;
#[cfg(feature = "client")]
use client::ClientError;
#[cfg(feature = "gateway")]
use gateway::GatewayError;
#[cfg(feature = "http")]
use http::HttpError;
#[cfg(feature = "voice")]
use voice::VoiceError;

/// The common result type between most library functions.
///
/// The library exposes functions which, for a result type, exposes only one
/// type, rather than the usual 2 (`Result<T, Error>`). This is because all
/// functions that return a result return serenity's [`Error`], so this is
/// implied, and a "simpler" result is used.
///
/// [`Error`]: enum.Error.html
pub type Result<T> = StdResult<T, Error>;

/// A common error enum returned by most of the library's functionality within a
/// custom [`Result`].
///
/// The most common error types, the [`ClientError`] and [`GatewayError`]
/// enums, are both wrapped around this in the form of the [`Client`] and
/// [`Gateway`] variants.
///
/// [`Client`]: #variant.Client
/// [`ClientError`]: client/enum.ClientError.html
/// [`Gateway`]: #variant.Gateway
/// [`GatewayError`]: gateway/enum.GatewayError.html
/// [`Result`]: type.Result.html
#[derive(Debug)]
pub enum Error {
    /// An error while decoding a payload.
    Decode(&'static str, Value),
    /// There was an error with a format.
    Format(FormatError),
    /// An `std::io` error.
    Io(IoError),
    /// An error from the `serde_json` crate.
    Json(JsonError),
    /// An error from the [`model`] module.
    ///
    /// [`model`]: model/index.html
    Model(ModelError),
    /// An error occurred while parsing an integer.
    Num(ParseIntError),
    /// Input exceeded a limit.
    /// Providing the input and the limit that's not supposed to be exceeded.
    ///
    /// *This only exists for the `GuildId::ban` and `Member::ban` functions. For their cases,
    /// it's the "reason".*
    ExceededLimit(String, u32),
    /// Some other error. This is only used for "Expected value <TYPE>" errors,
    /// when a more detailed error can not be easily provided via the
    /// [`Error::Decode`] variant.
    ///
    /// [`Error::Decode`]: #variant.Decode
    Other(&'static str),
    /// An error from the `url` crate.
    Url(String),
    /// A [client] error.
    ///
    /// [client]: client/index.html
    #[cfg(feature = "client")]
    Client(ClientError),
    /// An error from the `gateway` module.
    #[cfg(feature = "gateway")]
    Gateway(GatewayError),
    /// An error from the [`http`] module.
    ///
    /// [`http`]: http/index.html
    #[cfg(feature = "http")]
    Http(HttpError),
    /// An error from the `hyper` crate.
    #[cfg(feature = "hyper")]
    Hyper(HyperError),
    /// An error from the `native-tls` crate.
    #[cfg(feature = "native-tls")]
    Tls(TlsError),
    /// An error from the `rust-websocket` crate.
    #[cfg(feature = "gateway")]
    WebSocket(WebSocketError),
    /// An error from the `opus` crate.
    #[cfg(feature = "voice")]
    Opus(OpusError),
    /// Indicating an error within the [voice module].
    ///
    /// [voice module]: voice/index.html
    #[cfg(feature = "voice")]
    Voice(VoiceError),
}

impl From<FormatError> for Error {
    fn from(e: FormatError) -> Error { Error::Format(e) }
}

#[cfg(feature = "gateway")]
impl From<GatewayError> for Error {
    fn from(e: GatewayError) -> Error { Error::Gateway(e) }
}

#[cfg(feature = "hyper")]
impl From<HyperError> for Error {
    fn from(e: HyperError) -> Error { Error::Hyper(e) }
}

impl From<IoError> for Error {
    fn from(e: IoError) -> Error { Error::Io(e) }
}

impl From<JsonError> for Error {
    fn from(e: JsonError) -> Error { Error::Json(e) }
}

impl From<ParseIntError> for Error {
    fn from(e: ParseIntError) -> Error { Error::Num(e) }
}

impl From<ModelError> for Error {
    fn from(e: ModelError) -> Error { Error::Model(e) }
}

#[cfg(feature = "voice")]
impl From<OpusError> for Error {
    fn from(e: OpusError) -> Error { Error::Opus(e) }
}

#[cfg(feature = "native-tls")]
impl From<TlsError> for Error {
    fn from(e: TlsError) -> Error { Error::Tls(e) }
}

#[cfg(feature = "gateway")]
impl From<WebSocketError> for Error {
    fn from(e: WebSocketError) -> Error { Error::WebSocket(e) }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref inner) => inner.fmt(f),
            Error::Json(ref inner) => inner.fmt(f),
            #[cfg(feature = "http")]
            Error::Hyper(ref inner) => inner.fmt(f),
            #[cfg(feature = "gateway")]
            Error::WebSocket(ref inner) => inner.fmt(f),
            #[cfg(feature = "voice")]
            Error::Opus(ref inner) => inner.fmt(f),
            _ => f.write_str(self.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Decode(msg, _) | Error::Other(msg) => msg,
            Error::ExceededLimit(..) => "Input exceeded a limit",
            Error::Format(ref inner) => inner.description(),
            Error::Io(ref inner) => inner.description(),
            Error::Json(ref inner) => inner.description(),
            Error::Model(ref inner) => inner.description(),
            Error::Num(ref inner) => inner.description(),
            Error::Url(ref inner) => inner,
            #[cfg(feature = "client")]
            Error::Client(ref inner) => inner.description(),
            #[cfg(feature = "gateway")]
            Error::Gateway(ref inner) => inner.description(),
            #[cfg(feature = "http")]
            Error::Http(ref inner) => inner.description(),
            #[cfg(feature = "http")]
            Error::Hyper(ref inner) => inner.description(),
            #[cfg(feature = "voice")]
            Error::Opus(ref inner) => inner.description(),
            #[cfg(feature = "native-tls")]
            Error::Tls(ref inner) => inner.description(),
            #[cfg(feature = "voice")]
            Error::Voice(_) => "Voice error",
            #[cfg(feature = "gateway")]
            Error::WebSocket(ref inner) => inner.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            #[cfg(feature = "http")]
            Error::Hyper(ref inner) => Some(inner),
            Error::Json(ref inner) => Some(inner),
            Error::Io(ref inner) => Some(inner),
            #[cfg(feature = "gateway")]
            Error::WebSocket(ref inner) => Some(inner),
            _ => None,
        }
    }
}
<commit_msg>Simplify Error's `Display` impl<commit_after>use serde_json::Error as JsonError;
use std::io::Error as IoError;
use std::error::Error as StdError;
use std::fmt::{self, Display, Error as FormatError};
use std::num::ParseIntError;
use internal::prelude::*;
use model::ModelError;

#[cfg(feature = "hyper")]
use hyper::Error as HyperError;
#[cfg(feature = "native-tls")]
use native_tls::Error as TlsError;
#[cfg(feature = "voice")]
use opus::Error as OpusError;
#[cfg(feature = "websocket")]
use websocket::result::WebSocketError;
#[cfg(feature = "client")]
use client::ClientError;
#[cfg(feature = "gateway")]
use gateway::GatewayError;
#[cfg(feature = "http")]
use http::HttpError;
#[cfg(feature = "voice")]
use voice::VoiceError;

/// The common result type between most library functions.
///
/// The library exposes functions which, for a result type, exposes only one
/// type, rather than the usual 2 (`Result<T, Error>`). This is because all
/// functions that return a result return serenity's [`Error`], so this is
/// implied, and a "simpler" result is used.
///
/// [`Error`]: enum.Error.html
pub type Result<T> = StdResult<T, Error>;

/// A common error enum returned by most of the library's functionality within a
/// custom [`Result`].
///
/// The most common error types, the [`ClientError`] and [`GatewayError`]
/// enums, are both wrapped around this in the form of the [`Client`] and
/// [`Gateway`] variants.
///
/// [`Client`]: #variant.Client
/// [`ClientError`]: client/enum.ClientError.html
/// [`Gateway`]: #variant.Gateway
/// [`GatewayError`]: gateway/enum.GatewayError.html
/// [`Result`]: type.Result.html
#[derive(Debug)]
pub enum Error {
    /// An error while decoding a payload.
    Decode(&'static str, Value),
    /// There was an error with a format.
    Format(FormatError),
    /// An `std::io` error.
    Io(IoError),
    /// An error from the `serde_json` crate.
    Json(JsonError),
    /// An error from the [`model`] module.
    ///
    /// [`model`]: model/index.html
    Model(ModelError),
    /// An error occurred while parsing an integer.
    Num(ParseIntError),
    /// Input exceeded a limit.
    /// Providing the input and the limit that's not supposed to be exceeded.
    ///
    /// *This only exists for the `GuildId::ban` and `Member::ban` functions. For their cases,
    /// it's the "reason".*
    ExceededLimit(String, u32),
    /// Some other error. This is only used for "Expected value <TYPE>" errors,
    /// when a more detailed error can not be easily provided via the
    /// [`Error::Decode`] variant.
    ///
    /// [`Error::Decode`]: #variant.Decode
    Other(&'static str),
    /// An error from the `url` crate.
    Url(String),
    /// A [client] error.
    ///
    /// [client]: client/index.html
    #[cfg(feature = "client")]
    Client(ClientError),
    /// An error from the `gateway` module.
    #[cfg(feature = "gateway")]
    Gateway(GatewayError),
    /// An error from the [`http`] module.
    ///
    /// [`http`]: http/index.html
    #[cfg(feature = "http")]
    Http(HttpError),
    /// An error from the `hyper` crate.
    #[cfg(feature = "hyper")]
    Hyper(HyperError),
    /// An error from the `native-tls` crate.
    #[cfg(feature = "native-tls")]
    Tls(TlsError),
    /// An error from the `rust-websocket` crate.
    #[cfg(feature = "gateway")]
    WebSocket(WebSocketError),
    /// An error from the `opus` crate.
    #[cfg(feature = "voice")]
    Opus(OpusError),
    /// Indicating an error within the [voice module].
    ///
    /// [voice module]: voice/index.html
    #[cfg(feature = "voice")]
    Voice(VoiceError),
}

impl From<FormatError> for Error {
    fn from(e: FormatError) -> Error { Error::Format(e) }
}

#[cfg(feature = "gateway")]
impl From<GatewayError> for Error {
    fn from(e: GatewayError) -> Error { Error::Gateway(e) }
}

#[cfg(feature = "hyper")]
impl From<HyperError> for Error {
    fn from(e: HyperError) -> Error { Error::Hyper(e) }
}

impl From<IoError> for Error {
    fn from(e: IoError) -> Error { Error::Io(e) }
}

impl From<JsonError> for Error {
    fn from(e: JsonError) -> Error { Error::Json(e) }
}

impl From<ParseIntError> for Error {
    fn from(e: ParseIntError) -> Error { Error::Num(e) }
}

impl From<ModelError> for Error {
    fn from(e: ModelError) -> Error { Error::Model(e) }
}

#[cfg(feature = "voice")]
impl From<OpusError> for Error {
    fn from(e: OpusError) -> Error { Error::Opus(e) }
}

#[cfg(feature = "native-tls")]
impl From<TlsError> for Error {
    fn from(e: TlsError) -> Error { Error::Tls(e) }
}

#[cfg(feature = "gateway")]
impl From<WebSocketError> for Error {
    fn from(e: WebSocketError) -> Error { Error::WebSocket(e) }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Decode(msg, _) | Error::Other(msg) => msg,
            Error::ExceededLimit(..) => "Input exceeded a limit",
            Error::Format(ref inner) => inner.description(),
            Error::Io(ref inner) => inner.description(),
            Error::Json(ref inner) => inner.description(),
            Error::Model(ref inner) => inner.description(),
            Error::Num(ref inner) => inner.description(),
            Error::Url(ref inner) => inner,
            #[cfg(feature = "client")]
            Error::Client(ref inner) => inner.description(),
            #[cfg(feature = "gateway")]
            Error::Gateway(ref inner) => inner.description(),
            #[cfg(feature = "http")]
            Error::Http(ref inner) => inner.description(),
            #[cfg(feature = "http")]
            Error::Hyper(ref inner) => inner.description(),
            #[cfg(feature = "voice")]
            Error::Opus(ref inner) => inner.description(),
            #[cfg(feature = "native-tls")]
            Error::Tls(ref inner) => inner.description(),
            #[cfg(feature = "voice")]
            Error::Voice(_) => "Voice error",
            #[cfg(feature = "gateway")]
            Error::WebSocket(ref inner) => inner.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            #[cfg(feature = "http")]
            Error::Hyper(ref inner) => Some(inner),
            Error::Json(ref inner) => Some(inner),
            Error::Io(ref inner) => Some(inner),
            #[cfg(feature = "gateway")]
            Error::WebSocket(ref inner) => Some(inner),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//! Error type for disasm6502 crate.
use std::error::Error;
use std::fmt;
use std::io;
use std::result;

/// Result type used throughout the crate.
pub type Result<T> = result::Result<T, Disasm6502Error>;

///Error type for disasm6502 crate.
#[derive(Debug)]
pub enum Disasm6502Error {
    /// I/O error
    Io(io::Error)
}

impl fmt::Display for Disasm6502Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Disasm6502Error::Io(ref err)    => err.fmt(f)
        }
    }
}

impl Error for Disasm6502Error {
    fn description(&self) -> &str {
        match *self {
            Disasm6502Error::Io(ref err)    => err.description(),
        }
    }
}

impl From<io::Error> for Disasm6502Error {
    fn from(err: io::Error) -> Disasm6502Error {
        Disasm6502Error::Io(err)
    }
}
<commit_msg>removed unused description<commit_after>//! Error type for disasm6502 crate.
use std::fmt;
use std::io;
use std::result;

/// Result type used throughout the crate.
pub type Result<T> = result::Result<T, Disasm6502Error>;

///Error type for disasm6502 crate.
#[derive(Debug)]
pub enum Disasm6502Error {
    /// I/O error
    Io(io::Error)
}

impl fmt::Display for Disasm6502Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Disasm6502Error::Io(ref err) => err.fmt(f)
        }
    }
}

impl From<io::Error> for Disasm6502Error {
    fn from(err: io::Error) -> Disasm6502Error {
        Disasm6502Error::Io(err)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use ansi_term::Colour;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorKind {
    UndefinedVar = 0,
}

#[derive(Debug, PartialEq)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

#[derive(Debug, PartialEq)]
pub struct Error(pub ErrorKind, pub ErrorLevel, pub &'static str);

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let colour_level = match self.1 {
            ErrorLevel::Info => Colour::Yellow.paint("Info"),

            // ansi_term does not have orange for some reason
            ErrorLevel::Warning => Colour::RGB(255, 210, 0).paint("Warning"),
            ErrorLevel::Error => Colour::Red.paint("Error"),
        };

        // TODO: Remove clone
        write!(f, "[{}] (E{}) {}", colour_level, self.0 as i32, self.2)
    }
}

#[derive(Debug)]
pub struct ErrorStack(pub Vec<Error>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.0 {
            // TODO: Remove this unwrap
            write!(f, "{}", error).unwrap();
        }

        write!(f, "")
    }
}
<commit_msg>Change Error struct level<commit_after>use std::fmt;
use ansi_term::Colour;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorKind {
    UndefinedVar = 0,
    TooFewArguments = 1,
}

#[derive(Debug, PartialEq)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

#[derive(Debug, PartialEq)]
pub struct Error(pub ErrorLevel, pub ErrorKind, pub &'static str);

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let colour_level = match self.0 {
            ErrorLevel::Info => Colour::Yellow.paint("Info"),

            // ansi_term does not have orange for some reason
            ErrorLevel::Warning => Colour::RGB(255, 210, 0).paint("Warning"),
            ErrorLevel::Error => Colour::Red.paint("Error"),
        };

        // TODO: Remove clone
        write!(f, "[{}] (E{}) {}", colour_level, self.1 as i32, self.2)
    }
}

#[derive(Debug)]
pub struct ErrorStack(pub Vec<Error>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.0 {
            // TODO: Remove this unwrap
            write!(f, "{}", error).unwrap();
        }

        write!(f, "")
    }
}
<|endoftext|>