<commit_before>use std::error::Error;
use std::fmt;
use std::io::Error as IOError;
use std::string::FromUtf8Error;

use serde_json::error::Error as SerdeError;
#[cfg(feature = "dir_source")]
use walkdir::Error as WalkdirError;

#[cfg(feature = "script_helper")]
use rhai::{EvalAltResult, ParseError};

/// Error when rendering data on template.
#[derive(Debug)]
pub struct RenderError {
    pub desc: String,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    cause: Option<Box<dyn Error + 'static>>,
}

impl fmt::Display for RenderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no) {
            (Some(line), Some(col)) => write!(
                f,
                "Error rendering \"{}\" line {}, col {}: {}",
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned(),),
                line,
                col,
                self.desc
            ),
            _ => write!(f, "{}", self.desc),
        }
    }
}

impl Error for RenderError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.cause.as_ref().map(|e| &**e as &(dyn Error + 'static))
    }
}

impl From<IOError> for RenderError {
    fn from(e: IOError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<SerdeError> for RenderError {
    fn from(e: SerdeError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<FromUtf8Error> for RenderError {
    fn from(e: FromUtf8Error) -> RenderError {
        RenderError::with(e)
    }
}

#[cfg(feature = "script_helper")]
impl From<Box<EvalAltResult>> for RenderError {
    fn from(e: Box<EvalAltResult>) -> RenderError {
        RenderError::with(e)
    }
}

impl RenderError {
    pub fn new<T: AsRef<str>>(desc: T) -> RenderError {
        RenderError {
            desc: desc.as_ref().to_owned(),
            template_name: None,
            line_no: None,
            column_no: None,
            cause: None,
        }
    }

    pub fn strict_error(path: Option<&String>) -> RenderError {
        let msg = match path {
            Some(path) => format!("Variable {:?} not found in strict mode.", path),
            None => "Value is missing in strict mode".to_owned(),
        };
        RenderError::new(&msg)
    }

    pub fn with<E>(cause: E) -> RenderError
    where
        E: Error + 'static,
    {
        let mut e = RenderError::new(cause.to_string());
        e.cause = Some(Box::new(cause));

        e
    }
}

quick_error! {
/// Template parsing error
    #[derive(PartialEq, Debug, Clone)]
    pub enum TemplateErrorReason {
        MismatchingClosedHelper(open: String, closed: String) {
            display("helper {:?} was opened, but {:?} is closing",
                open, closed)
        }
        MismatchingClosedDecorator(open: String, closed: String) {
            display("decorator {:?} was opened, but {:?} is closing",
                open, closed)
        }
        InvalidSyntax {
            display("invalid handlebars syntax.")
        }
        InvalidParam (param: String) {
            display("invalid parameter {:?}", param)
        }
        NestedSubexpression {
            display("nested subexpression is not supported")
        }
    }
}

/// Error on parsing template.
#[derive(Debug, PartialEq)]
pub struct TemplateError {
    pub reason: TemplateErrorReason,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    segment: Option<String>,
}

impl TemplateError {
    pub fn of(e: TemplateErrorReason) -> TemplateError {
        TemplateError {
            reason: e,
            template_name: None,
            line_no: None,
            column_no: None,
            segment: None,
        }
    }

    pub fn at(mut self, template_str: &str, line_no: usize, column_no: usize) -> TemplateError {
        self.line_no = Some(line_no);
        self.column_no = Some(column_no);
        self.segment = Some(template_segment(template_str, line_no, column_no));
        self
    }

    pub fn in_template(mut self, name: String) -> TemplateError {
        self.template_name = Some(name);
        self
    }
}

impl Error for TemplateError {}

fn template_segment(template_str: &str, line: usize, col: usize) -> String {
    let range = 3;
    let line_start = if line >= range { line - range } else { 0 };
    let line_end = line + range;

    let mut buf = String::new();
    for (line_count, line_content) in template_str.lines().enumerate() {
        if line_count >= line_start && line_count <= line_end {
            buf.push_str(&format!("{:4} | {}\n", line_count, line_content));
            if line_count == line - 1 {
                buf.push_str("     |");
                for c in 0..line_content.len() {
                    if c != col {
                        buf.push_str("-");
                    } else {
                        buf.push_str("^");
                    }
                }
                buf.push_str("\n");
            }
        }
    }

    buf
}

impl fmt::Display for TemplateError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no, &self.segment) {
            (Some(line), Some(col), &Some(ref seg)) => writeln!(
                f,
                "Template error: {}\n    --> Template error in \"{}\":{}:{}\n     |\n{}     |\n     = reason: {}",
                self.reason,
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned()),
                line,
                col,
                seg,
                self.reason
            ),
            _ => write!(f, "{}", self.reason),
        }
    }
}

quick_error! {
    /// A combined error type for `TemplateError` and `IOError`
    #[derive(Debug)]
    pub enum TemplateFileError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

#[cfg(feature = "dir_source")]
impl From<WalkdirError> for TemplateFileError {
    fn from(error: WalkdirError) -> TemplateFileError {
        let path_string: String = error
            .path()
            .map(|p| p.to_string_lossy().to_string())
            .unwrap_or_default();
        TemplateFileError::IOError(IOError::from(error), path_string)
    }
}

quick_error! {
    /// A combined error type for `TemplateError`, `IOError` and `RenderError`
    #[derive(Debug)]
    pub enum TemplateRenderError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        RenderError(err: RenderError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

impl TemplateRenderError {
    pub fn as_render_error(&self) -> Option<&RenderError> {
        if let TemplateRenderError::RenderError(ref e) = *self {
            Some(&e)
        } else {
            None
        }
    }
}

#[cfg(feature = "script_helper")]
quick_error! {
    #[derive(Debug)]
    pub enum ScriptError {
        IOError(err: IOError) {
            from()
            cause(err)
        }
        ParseError(err: Box<ParseError>) {
            from()
            cause(err)
        }
    }
}
<commit_msg>(fix) add Send + Sync back for #327<commit_after>use std::error::Error;
use std::fmt;
use std::io::Error as IOError;
use std::string::FromUtf8Error;

use serde_json::error::Error as SerdeError;
#[cfg(feature = "dir_source")]
use walkdir::Error as WalkdirError;

#[cfg(feature = "script_helper")]
use rhai::{EvalAltResult, ParseError};

/// Error when rendering data on template.
#[derive(Debug)]
pub struct RenderError {
    pub desc: String,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    cause: Option<Box<dyn Error + Send + Sync + 'static>>,
}

impl fmt::Display for RenderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no) {
            (Some(line), Some(col)) => write!(
                f,
                "Error rendering \"{}\" line {}, col {}: {}",
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned(),),
                line,
                col,
                self.desc
            ),
            _ => write!(f, "{}", self.desc),
        }
    }
}

impl Error for RenderError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.cause.as_ref().map(|e| &**e as &(dyn Error + 'static))
    }
}

impl From<IOError> for RenderError {
    fn from(e: IOError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<SerdeError> for RenderError {
    fn from(e: SerdeError) -> RenderError {
        RenderError::with(e)
    }
}

impl From<FromUtf8Error> for RenderError {
    fn from(e: FromUtf8Error) -> RenderError {
        RenderError::with(e)
    }
}

#[cfg(feature = "script_helper")]
impl From<Box<EvalAltResult>> for RenderError {
    fn from(e: Box<EvalAltResult>) -> RenderError {
        RenderError::with(e)
    }
}

impl RenderError {
    pub fn new<T: AsRef<str>>(desc: T) -> RenderError {
        RenderError {
            desc: desc.as_ref().to_owned(),
            template_name: None,
            line_no: None,
            column_no: None,
            cause: None,
        }
    }

    pub fn strict_error(path: Option<&String>) -> RenderError {
        let msg = match path {
            Some(path) => format!("Variable {:?} not found in strict mode.", path),
            None => "Value is missing in strict mode".to_owned(),
        };
        RenderError::new(&msg)
    }

    pub fn with<E>(cause: E) -> RenderError
    where
        E: Error + Send + Sync + 'static,
    {
        let mut e = RenderError::new(cause.to_string());
        e.cause = Some(Box::new(cause));

        e
    }
}

quick_error! {
/// Template parsing error
    #[derive(PartialEq, Debug, Clone)]
    pub enum TemplateErrorReason {
        MismatchingClosedHelper(open: String, closed: String) {
            display("helper {:?} was opened, but {:?} is closing",
                open, closed)
        }
        MismatchingClosedDecorator(open: String, closed: String) {
            display("decorator {:?} was opened, but {:?} is closing",
                open, closed)
        }
        InvalidSyntax {
            display("invalid handlebars syntax.")
        }
        InvalidParam (param: String) {
            display("invalid parameter {:?}", param)
        }
        NestedSubexpression {
            display("nested subexpression is not supported")
        }
    }
}

/// Error on parsing template.
#[derive(Debug, PartialEq)]
pub struct TemplateError {
    pub reason: TemplateErrorReason,
    pub template_name: Option<String>,
    pub line_no: Option<usize>,
    pub column_no: Option<usize>,
    segment: Option<String>,
}

impl TemplateError {
    pub fn of(e: TemplateErrorReason) -> TemplateError {
        TemplateError {
            reason: e,
            template_name: None,
            line_no: None,
            column_no: None,
            segment: None,
        }
    }

    pub fn at(mut self, template_str: &str, line_no: usize, column_no: usize) -> TemplateError {
        self.line_no = Some(line_no);
        self.column_no = Some(column_no);
        self.segment = Some(template_segment(template_str, line_no, column_no));
        self
    }

    pub fn in_template(mut self, name: String) -> TemplateError {
        self.template_name = Some(name);
        self
    }
}

impl Error for TemplateError {}

fn template_segment(template_str: &str, line: usize, col: usize) -> String {
    let range = 3;
    let line_start = if line >= range { line - range } else { 0 };
    let line_end = line + range;

    let mut buf = String::new();
    for (line_count, line_content) in template_str.lines().enumerate() {
        if line_count >= line_start && line_count <= line_end {
            buf.push_str(&format!("{:4} | {}\n", line_count, line_content));
            if line_count == line - 1 {
                buf.push_str("     |");
                for c in 0..line_content.len() {
                    if c != col {
                        buf.push_str("-");
                    } else {
                        buf.push_str("^");
                    }
                }
                buf.push_str("\n");
            }
        }
    }

    buf
}

impl fmt::Display for TemplateError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match (self.line_no, self.column_no, &self.segment) {
            (Some(line), Some(col), &Some(ref seg)) => writeln!(
                f,
                "Template error: {}\n    --> Template error in \"{}\":{}:{}\n     |\n{}     |\n     = reason: {}",
                self.reason,
                self.template_name
                    .as_ref()
                    .unwrap_or(&"Unnamed template".to_owned()),
                line,
                col,
                seg,
                self.reason
            ),
            _ => write!(f, "{}", self.reason),
        }
    }
}

quick_error! {
    /// A combined error type for `TemplateError` and `IOError`
    #[derive(Debug)]
    pub enum TemplateFileError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

#[cfg(feature = "dir_source")]
impl From<WalkdirError> for TemplateFileError {
    fn from(error: WalkdirError) -> TemplateFileError {
        let path_string: String = error
            .path()
            .map(|p| p.to_string_lossy().to_string())
            .unwrap_or_default();
        TemplateFileError::IOError(IOError::from(error), path_string)
    }
}

quick_error! {
    /// A combined error type for `TemplateError`, `IOError` and `RenderError`
    #[derive(Debug)]
    pub enum TemplateRenderError {
        TemplateError(err: TemplateError) {
            from()
            cause(err)
            display("{}", err)
        }
        RenderError(err: RenderError) {
            from()
            cause(err)
            display("{}", err)
        }
        IOError(err: IOError, name: String) {
            cause(err)
            display("Template \"{}\": {}", name, err)
        }
    }
}

impl TemplateRenderError {
    pub fn as_render_error(&self) -> Option<&RenderError> {
        if let TemplateRenderError::RenderError(ref e) = *self {
            Some(&e)
        } else {
            None
        }
    }
}

#[cfg(feature = "script_helper")]
quick_error! {
    #[derive(Debug)]
    pub enum ScriptError {
        IOError(err: IOError) {
            from()
            cause(err)
        }
        ParseError(err: Box<ParseError>) {
            from()
            cause(err)
        }
    }
}
<|endoftext|>


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

use std::io;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum Error {
    NoMemory,
    InvalidRestore,
    InvalidPopGroup,
    NoCurrentPoint,
    InvalidMatrix,
    InvalidStatus,
    NullPointer,
    InvalidString,
    InvalidPathData,
    ReadError,
    WriteError,
    SurfaceFinished,
    SurfaceTypeMismatch,
    PatternTypeMismatch,
    InvalidContent,
    InvalidFormat,
    InvalidVisual,
    FileNotFound,
    InvalidDash,
    InvalidDscComment,
    InvalidIndex,
    ClipNotRepresentable,
    TempFileError,
    InvalidStride,
    FontTypeMismatch,
    UserFontImmutable,
    UserFontError,
    NegativeCount,
    InvalidClusters,
    InvalidSlant,
    InvalidWeight,
    InvalidSize,
    UserFontNotImplemented,
    DeviceTypeMismatch,
    DeviceError,
    InvalidMeshConstruction,
    DeviceFinished,
    JBig2GlobalMissing,
    PngError,
    FreetypeError,
    Win32GdiError,
    LastStatus,
    __Unknown(i32),
}
#[doc(hidden)]
impl Into<ffi::cairo_status_t> for Error {
    fn into(self) -> ffi::cairo_status_t {
        match self {
            Error::NoMemory => ffi::STATUS_NO_MEMORY,
            Error::InvalidRestore => ffi::STATUS_INVALID_RESTORE,
            Error::InvalidPopGroup => ffi::STATUS_INVALID_POP_GROUP,
            Error::NoCurrentPoint => ffi::STATUS_NO_CURRENT_POINT,
            Error::InvalidMatrix => ffi::STATUS_INVALID_MATRIX,
            Error::InvalidStatus => ffi::STATUS_INVALID_STATUS,
            Error::NullPointer => ffi::STATUS_NULL_POINTER,
            Error::InvalidString => ffi::STATUS_INVALID_STRING,
            Error::InvalidPathData => ffi::STATUS_INVALID_PATH_DATA,
            Error::ReadError => ffi::STATUS_READ_ERROR,
            Error::WriteError => ffi::STATUS_WRITE_ERROR,
            Error::SurfaceFinished => ffi::STATUS_SURFACE_FINISHED,
            Error::SurfaceTypeMismatch => ffi::STATUS_SURFACE_TYPE_MISMATCH,
            Error::PatternTypeMismatch => ffi::STATUS_PATTERN_TYPE_MISMATCH,
            Error::InvalidContent => ffi::STATUS_INVALID_CONTENT,
            Error::InvalidFormat => ffi::STATUS_INVALID_FORMAT,
            Error::InvalidVisual => ffi::STATUS_INVALID_VISUAL,
            Error::FileNotFound => ffi::STATUS_FILE_NOT_FOUND,
            Error::InvalidDash => ffi::STATUS_INVALID_DASH,
            Error::InvalidDscComment => ffi::STATUS_INVALID_DSC_COMMENT,
            Error::InvalidIndex => ffi::STATUS_INVALID_INDEX,
            Error::ClipNotRepresentable => ffi::STATUS_CLIP_NOT_REPRESENTABLE,
            Error::TempFileError => ffi::STATUS_TEMP_FILE_ERROR,
            Error::InvalidStride => ffi::STATUS_INVALID_STRIDE,
            Error::FontTypeMismatch => ffi::STATUS_FONT_TYPE_MISMATCH,
            Error::UserFontImmutable => ffi::STATUS_USER_FONT_IMMUTABLE,
            Error::UserFontError => ffi::STATUS_USER_FONT_ERROR,
            Error::NegativeCount => ffi::STATUS_NEGATIVE_COUNT,
            Error::InvalidClusters => ffi::STATUS_INVALID_CLUSTERS,
            Error::InvalidSlant => ffi::STATUS_INVALID_SLANT,
            Error::InvalidWeight => ffi::STATUS_INVALID_WEIGHT,
            Error::InvalidSize => ffi::STATUS_INVALID_SIZE,
            Error::UserFontNotImplemented => ffi::STATUS_USER_FONT_NOT_IMPLEMENTED,
            Error::DeviceTypeMismatch => ffi::STATUS_DEVICE_TYPE_MISMATCH,
            Error::DeviceError => ffi::STATUS_DEVICE_ERROR,
            Error::InvalidMeshConstruction => ffi::STATUS_INVALID_MESH_CONSTRUCTION,
            Error::DeviceFinished => ffi::STATUS_DEVICE_FINISHED,
            Error::JBig2GlobalMissing => ffi::STATUS_J_BIG2_GLOBAL_MISSING,
            Error::PngError => ffi::STATUS_PNG_ERROR,
            Error::FreetypeError => ffi::STATUS_FREETYPE_ERROR,
            Error::Win32GdiError => ffi::STATUS_WIN32_GDI_ERROR,
            Error::LastStatus => ffi::STATUS_LAST_STATUS,
            Error::__Unknown(value) => value,
        }
    }
}

#[doc(hidden)]
impl From<ffi::cairo_status_t> for Error {
    fn from(value: ffi::cairo_status_t) -> Self {
        match value {
            ffi::STATUS_NO_MEMORY => Error::NoMemory,
            ffi::STATUS_INVALID_RESTORE => Error::InvalidRestore,
            ffi::STATUS_INVALID_POP_GROUP => Error::InvalidPopGroup,
            ffi::STATUS_NO_CURRENT_POINT => Error::NoCurrentPoint,
            ffi::STATUS_INVALID_MATRIX => Error::InvalidMatrix,
            ffi::STATUS_INVALID_STATUS => Error::InvalidStatus,
            ffi::STATUS_NULL_POINTER => Error::NullPointer,
            ffi::STATUS_INVALID_STRING => Error::InvalidString,
            ffi::STATUS_INVALID_PATH_DATA => Error::InvalidPathData,
            ffi::STATUS_READ_ERROR => Error::ReadError,
            ffi::STATUS_WRITE_ERROR => Error::WriteError,
            ffi::STATUS_SURFACE_FINISHED => Error::SurfaceFinished,
            ffi::STATUS_SURFACE_TYPE_MISMATCH => Error::SurfaceTypeMismatch,
            ffi::STATUS_PATTERN_TYPE_MISMATCH => Error::PatternTypeMismatch,
            ffi::STATUS_INVALID_CONTENT => Error::InvalidContent,
            ffi::STATUS_INVALID_FORMAT => Error::InvalidFormat,
            ffi::STATUS_INVALID_VISUAL => Error::InvalidVisual,
            ffi::STATUS_FILE_NOT_FOUND => Error::FileNotFound,
            ffi::STATUS_INVALID_DASH => Error::InvalidDash,
            ffi::STATUS_INVALID_DSC_COMMENT => Error::InvalidDscComment,
            ffi::STATUS_INVALID_INDEX => Error::InvalidIndex,
            ffi::STATUS_CLIP_NOT_REPRESENTABLE => Error::ClipNotRepresentable,
            ffi::STATUS_TEMP_FILE_ERROR => Error::TempFileError,
            ffi::STATUS_INVALID_STRIDE => Error::InvalidStride,
            ffi::STATUS_FONT_TYPE_MISMATCH => Error::FontTypeMismatch,
            ffi::STATUS_USER_FONT_IMMUTABLE => Error::UserFontImmutable,
            ffi::STATUS_USER_FONT_ERROR => Error::UserFontError,
            ffi::STATUS_NEGATIVE_COUNT => Error::NegativeCount,
            ffi::STATUS_INVALID_CLUSTERS => Error::InvalidClusters,
            ffi::STATUS_INVALID_SLANT => Error::InvalidSlant,
            ffi::STATUS_INVALID_WEIGHT => Error::InvalidWeight,
            ffi::STATUS_INVALID_SIZE => Error::InvalidSize,
            ffi::STATUS_USER_FONT_NOT_IMPLEMENTED => Error::UserFontNotImplemented,
            ffi::STATUS_DEVICE_TYPE_MISMATCH => Error::DeviceTypeMismatch,
            ffi::STATUS_DEVICE_ERROR => Error::DeviceError,
            ffi::STATUS_INVALID_MESH_CONSTRUCTION => Error::InvalidMeshConstruction,
            ffi::STATUS_DEVICE_FINISHED => Error::DeviceFinished,
            ffi::STATUS_J_BIG2_GLOBAL_MISSING => Error::JBig2GlobalMissing,
            ffi::STATUS_PNG_ERROR => Error::PngError,
            ffi::STATUS_FREETYPE_ERROR => Error::FreetypeError,
            ffi::STATUS_WIN32_GDI_ERROR => Error::Win32GdiError,
            ffi::STATUS_LAST_STATUS => Error::LastStatus,
            value => Error::__Unknown(value),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Error::{}",
            match *self {
                Error::NoMemory => "NoMemory",
                Error::InvalidRestore => "InvalidRestore",
                Error::InvalidPopGroup => "InvalidPopGroup",
                Error::NoCurrentPoint => "NoCurrentPoint",
                Error::InvalidMatrix => "InvalidMatrix",
                Error::InvalidStatus => "InvalidStatus",
                Error::NullPointer => "NullPointer",
                Error::InvalidString => "InvalidString",
                Error::InvalidPathData => "InvalidPathData",
                Error::ReadError => "ReadError",
                Error::WriteError => "WriteError",
                Error::SurfaceFinished => "SurfaceFinished",
                Error::SurfaceTypeMismatch => "SurfaceTypeMismatch",
                Error::PatternTypeMismatch => "PatternTypeMismatch",
                Error::InvalidContent => "InvalidContent",
                Error::InvalidFormat => "InvalidFormat",
                Error::InvalidVisual => "InvalidVisual",
                Error::FileNotFound => "FileNotFound",
                Error::InvalidDash => "InvalidDash",
                Error::InvalidDscComment => "InvalidDscComment",
                Error::InvalidIndex => "InvalidIndex",
                Error::ClipNotRepresentable => "ClipNotRepresentable",
                Error::TempFileError => "TempFileError",
                Error::InvalidStride => "InvalidStride",
                Error::FontTypeMismatch => "FontTypeMismatch",
                Error::UserFontImmutable => "UserFontImmutable",
                Error::UserFontError => "UserFontError",
                Error::NegativeCount => "NegativeCount",
                Error::InvalidClusters => "InvalidClusters",
                Error::InvalidSlant => "InvalidSlant",
                Error::InvalidWeight => "InvalidWeight",
                Error::InvalidSize => "InvalidSize",
                Error::UserFontNotImplemented => "UserFontNotImplemented",
                Error::DeviceTypeMismatch => "DeviceTypeMismatch",
                Error::DeviceError => "DeviceError",
                Error::InvalidMeshConstruction => "InvalidMeshConstruction",
                Error::DeviceFinished => "DeviceFinished",
                Error::JBig2GlobalMissing => "JBig2GlobalMissing",
                Error::PngError => "PngError",
                Error::FreetypeError => "FreetypeError",
                Error::Win32GdiError => "Win32GdiError",
                Error::LastStatus => "LastStatus",
                _ => "Unknown",
            }
        )
    }
}

#[derive(Error, Debug)]
pub enum IoError {
    #[error("Cairo error: {0}")]
    Cairo(#[from] Error),
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
}

#[derive(Error, Debug)]
pub enum BorrowError {
    #[error("Failed to borrow with Cairo error: {0}")]
    Cairo(#[from] ::Error),
    #[error("Can't get exclusive access")]
    NonExclusive,
}
<commit_msg>cairo::Error: use thiserror to implement Debug<commit_after>// Copyright 2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
use std::fmt::Debug;

use std::io;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum Error {
    #[error("Cairo: No Memory")]
    NoMemory,
    #[error("Cairo: Invalid Restore")]
    InvalidRestore,
    #[error("Cairo: Invalid Pop Group")]
    InvalidPopGroup,
    #[error("Cairo: No Current Point")]
    NoCurrentPoint,
    #[error("Cairo: Invalid Matrix")]
    InvalidMatrix,
    #[error("Cairo: Invalid Status")]
    InvalidStatus,
    #[error("Cairo: Null Pointer")]
    NullPointer,
    #[error("Cairo: Invalid String")]
    InvalidString,
    #[error("Cairo: Invalid Path Data")]
    InvalidPathData,
    #[error("Cairo : Read Error")]
    ReadError,
    #[error("Cairo: Write Error")]
    WriteError,
    #[error("Cairo: Surface Finishied")]
    SurfaceFinished,
    #[error("Cairo: Surface Type Mismatch")]
    SurfaceTypeMismatch,
    #[error("Cairo: Pattern Type Mismatch")]
    PatternTypeMismatch,
    #[error("Cairo: Invalid Content")]
    InvalidContent,
    #[error("Cairo: Invalid Format")]
    InvalidFormat,
    #[error("Cairo: Invalid Visual")]
    InvalidVisual,
    #[error("Cairo: File Not Found")]
    FileNotFound,
    #[error("Cairo: Invalid Dash")]
    InvalidDash,
    #[error("Cairo: Invalid Dash Comment")]
    InvalidDscComment,
    #[error("Cairo: Invalid Index")]
    InvalidIndex,
    #[error("Cairo: Clip Not Representable")]
    ClipNotRepresentable,
    #[error("Cairo: Temp File Error")]
    TempFileError,
    #[error("Cairo: Invalid Stride")]
    InvalidStride,
    #[error("Cairo: Font Type Mismatch")]
    FontTypeMismatch,
    #[error("Cairo: User Font Immutable")]
    UserFontImmutable,
    #[error("Cairo: User Font Error")]
    UserFontError,
    #[error("Cairo: Negative Count")]
    NegativeCount,
    #[error("Cairo: Invalid Clusters")]
    InvalidClusters,
    #[error("Cairo: Invalid Slant")]
    InvalidSlant,
    #[error("Cairo: Invalid Weight")]
    InvalidWeight,
    #[error("Cairo: Ivalid Size")]
    InvalidSize,
    #[error("Cairo: User Font Not Implemented")]
    UserFontNotImplemented,
    #[error("Cairo: Device Type Mismatch")]
    DeviceTypeMismatch,
    #[error("Cairo: Device Error")]
    DeviceError,
    #[error("Cairo: Invalid Mesh Construction")]
    InvalidMeshConstruction,
    #[error("Cairo: Device Finished")]
    DeviceFinished,
    #[error("Cairo: JBig2Global Missing")]
    JBig2GlobalMissing,
    #[error("Cairo: PNG Error")]
    PngError,
    #[error("Cairo: Freetype Error")]
    FreetypeError,
    #[error("Cairo: Win32Gdi Error")]
    Win32GdiError,
    #[error("Cairo: LastStatus")]
    LastStatus,
    #[error("Cairo: Uknown {0}")]
    __Unknown(i32),
}
#[doc(hidden)]
impl Into<ffi::cairo_status_t> for Error {
    fn into(self) -> ffi::cairo_status_t {
        match self {
            Error::NoMemory => ffi::STATUS_NO_MEMORY,
            Error::InvalidRestore => ffi::STATUS_INVALID_RESTORE,
            Error::InvalidPopGroup => ffi::STATUS_INVALID_POP_GROUP,
            Error::NoCurrentPoint => ffi::STATUS_NO_CURRENT_POINT,
            Error::InvalidMatrix => ffi::STATUS_INVALID_MATRIX,
            Error::InvalidStatus => ffi::STATUS_INVALID_STATUS,
            Error::NullPointer => ffi::STATUS_NULL_POINTER,
            Error::InvalidString => ffi::STATUS_INVALID_STRING,
            Error::InvalidPathData => ffi::STATUS_INVALID_PATH_DATA,
            Error::ReadError => ffi::STATUS_READ_ERROR,
            Error::WriteError => ffi::STATUS_WRITE_ERROR,
            Error::SurfaceFinished => ffi::STATUS_SURFACE_FINISHED,
            Error::SurfaceTypeMismatch => ffi::STATUS_SURFACE_TYPE_MISMATCH,
            Error::PatternTypeMismatch => ffi::STATUS_PATTERN_TYPE_MISMATCH,
            Error::InvalidContent => ffi::STATUS_INVALID_CONTENT,
            Error::InvalidFormat => ffi::STATUS_INVALID_FORMAT,
            Error::InvalidVisual => ffi::STATUS_INVALID_VISUAL,
            Error::FileNotFound => ffi::STATUS_FILE_NOT_FOUND,
            Error::InvalidDash => ffi::STATUS_INVALID_DASH,
            Error::InvalidDscComment => ffi::STATUS_INVALID_DSC_COMMENT,
            Error::InvalidIndex => ffi::STATUS_INVALID_INDEX,
            Error::ClipNotRepresentable => ffi::STATUS_CLIP_NOT_REPRESENTABLE,
            Error::TempFileError => ffi::STATUS_TEMP_FILE_ERROR,
            Error::InvalidStride => ffi::STATUS_INVALID_STRIDE,
            Error::FontTypeMismatch => ffi::STATUS_FONT_TYPE_MISMATCH,
            Error::UserFontImmutable => ffi::STATUS_USER_FONT_IMMUTABLE,
            Error::UserFontError => ffi::STATUS_USER_FONT_ERROR,
            Error::NegativeCount => ffi::STATUS_NEGATIVE_COUNT,
            Error::InvalidClusters => ffi::STATUS_INVALID_CLUSTERS,
            Error::InvalidSlant => ffi::STATUS_INVALID_SLANT,
            Error::InvalidWeight => ffi::STATUS_INVALID_WEIGHT,
            Error::InvalidSize => ffi::STATUS_INVALID_SIZE,
            Error::UserFontNotImplemented => ffi::STATUS_USER_FONT_NOT_IMPLEMENTED,
            Error::DeviceTypeMismatch => ffi::STATUS_DEVICE_TYPE_MISMATCH,
            Error::DeviceError => ffi::STATUS_DEVICE_ERROR,
            Error::InvalidMeshConstruction => ffi::STATUS_INVALID_MESH_CONSTRUCTION,
            Error::DeviceFinished => ffi::STATUS_DEVICE_FINISHED,
            Error::JBig2GlobalMissing => ffi::STATUS_J_BIG2_GLOBAL_MISSING,
            Error::PngError => ffi::STATUS_PNG_ERROR,
            Error::FreetypeError => ffi::STATUS_FREETYPE_ERROR,
            Error::Win32GdiError => ffi::STATUS_WIN32_GDI_ERROR,
            Error::LastStatus => ffi::STATUS_LAST_STATUS,
            Error::__Unknown(value) => value,
        }
    }
}

#[doc(hidden)]
impl From<ffi::cairo_status_t> for Error {
    fn from(value: ffi::cairo_status_t) -> Self {
        match value {
            ffi::STATUS_NO_MEMORY => Error::NoMemory,
            ffi::STATUS_INVALID_RESTORE => Error::InvalidRestore,
            ffi::STATUS_INVALID_POP_GROUP => Error::InvalidPopGroup,
            ffi::STATUS_NO_CURRENT_POINT => Error::NoCurrentPoint,
            ffi::STATUS_INVALID_MATRIX => Error::InvalidMatrix,
            ffi::STATUS_INVALID_STATUS => Error::InvalidStatus,
            ffi::STATUS_NULL_POINTER => Error::NullPointer,
            ffi::STATUS_INVALID_STRING => Error::InvalidString,
            ffi::STATUS_INVALID_PATH_DATA => Error::InvalidPathData,
            ffi::STATUS_READ_ERROR => Error::ReadError,
            ffi::STATUS_WRITE_ERROR => Error::WriteError,
            ffi::STATUS_SURFACE_FINISHED => Error::SurfaceFinished,
            ffi::STATUS_SURFACE_TYPE_MISMATCH => Error::SurfaceTypeMismatch,
            ffi::STATUS_PATTERN_TYPE_MISMATCH => Error::PatternTypeMismatch,
            ffi::STATUS_INVALID_CONTENT => Error::InvalidContent,
            ffi::STATUS_INVALID_FORMAT => Error::InvalidFormat,
            ffi::STATUS_INVALID_VISUAL => Error::InvalidVisual,
            ffi::STATUS_FILE_NOT_FOUND => Error::FileNotFound,
            ffi::STATUS_INVALID_DASH => Error::InvalidDash,
            ffi::STATUS_INVALID_DSC_COMMENT => Error::InvalidDscComment,
            ffi::STATUS_INVALID_INDEX => Error::InvalidIndex,
            ffi::STATUS_CLIP_NOT_REPRESENTABLE => Error::ClipNotRepresentable,
            ffi::STATUS_TEMP_FILE_ERROR => Error::TempFileError,
            ffi::STATUS_INVALID_STRIDE => Error::InvalidStride,
            ffi::STATUS_FONT_TYPE_MISMATCH => Error::FontTypeMismatch,
            ffi::STATUS_USER_FONT_IMMUTABLE => Error::UserFontImmutable,
            ffi::STATUS_USER_FONT_ERROR => Error::UserFontError,
            ffi::STATUS_NEGATIVE_COUNT => Error::NegativeCount,
            ffi::STATUS_INVALID_CLUSTERS => Error::InvalidClusters,
            ffi::STATUS_INVALID_SLANT => Error::InvalidSlant,
            ffi::STATUS_INVALID_WEIGHT => Error::InvalidWeight,
            ffi::STATUS_INVALID_SIZE => Error::InvalidSize,
            ffi::STATUS_USER_FONT_NOT_IMPLEMENTED => Error::UserFontNotImplemented,
            ffi::STATUS_DEVICE_TYPE_MISMATCH => Error::DeviceTypeMismatch,
            ffi::STATUS_DEVICE_ERROR => Error::DeviceError,
            ffi::STATUS_INVALID_MESH_CONSTRUCTION => Error::InvalidMeshConstruction,
            ffi::STATUS_DEVICE_FINISHED => Error::DeviceFinished,
            ffi::STATUS_J_BIG2_GLOBAL_MISSING => Error::JBig2GlobalMissing,
            ffi::STATUS_PNG_ERROR => Error::PngError,
            ffi::STATUS_FREETYPE_ERROR => Error::FreetypeError,
            ffi::STATUS_WIN32_GDI_ERROR => Error::Win32GdiError,
            ffi::STATUS_LAST_STATUS => Error::LastStatus,
            value => Error::__Unknown(value),
        }
    }
}

#[derive(Error, Debug)]
pub enum IoError {
    #[error("Cairo error: {0}")]
    Cairo(#[from] Error),
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
}

#[derive(Error, Debug)]
pub enum BorrowError {
    #[error("Failed to borrow with Cairo error: {0}")]
    Cairo(#[from] ::Error),
    #[error("Can't get exclusive access")]
    NonExclusive,
}
<|endoftext|>


<commit_before>use std::fmt::{self, Formatter};
use std::io::{self, ErrorKind};
use std::path::{self, Path};
use std::string;

use parser;

/// An enum of all error kinds.
#[derive(Debug)]
pub enum Error {
    /// An error for when a type cannot be parsed to a string because it
    /// contains invalid UTF-8.
    InvalidUtf8,
    /// An IO error was encountered.
    IoError(io::Error),
    /// An error which occurs when a path which is expected to contain a file
    /// name as the final component instead terminates in `.`, `..`, or solely
    /// of a root of prefix.
    MissingFileName,
    /// An error for when the template field is expected but not specified in a
    /// document header.
    MissingTemplateField,
    /// Wraps errors emitted by methods when attempting to parse a document.
    ParserError(parser::Error),
    /// Wraps errors emitted by the `Path::strip_prefix` method.
    StripPrefixError(path::StripPrefixError),
    /// An error which occurs when a specified template cannot be found.
    TemplateNotFound,
}

impl Error {
    /// Create an error for a non-directory path which was expected to be as
    /// directory.
    pub fn path_is_not_a_directory<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::InvalidInput, format!(
                    "specified path is not a directory: {}",
                    path.as_ref().display(),
                )))
    }

    /// Create an error for a path which unexpectedly points at a non-existing
    /// entity.
    pub fn path_not_found<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::NotFound, format!(
                    "specified path not found: {}",
                    path.as_ref().display(),
                )))
    }
}

/// Application generic result type.
pub type Result<T> = ::std::result::Result<T, self::Error>;

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

impl From<parser::Error> for Error {
    fn from(error: parser::Error) -> Error {
        Error::ParserError(error)
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_error: string::FromUtf8Error) -> Error {
        Error::InvalidUtf8
    }
}

impl From<path::StripPrefixError> for Error {
    fn from(error: path::StripPrefixError) -> Error {
        Error::StripPrefixError(error)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        match *self {
            Error::InvalidUtf8 => "a string is not valid UTF-8".fmt(formatter),
            Error::IoError(ref e) => e.fmt(formatter),
            Error::MissingFileName => "a path is missing a file name".fmt(formatter),
            Error::MissingTemplateField => "missing template field in header".fmt(formatter),
            Error::ParserError(ref e) => e.fmt(formatter),
            Error::StripPrefixError(ref e) => e.fmt(formatter),
            Error::TemplateNotFound => "specified template could not be found".fmt(formatter),
        }
    }
}

// Implement `PartialEq` manually, since `std::io::Error` does not implement it.
impl PartialEq<Error> for Error {
    fn eq(&self, other: &Error) -> bool {
        use self::Error::{
            InvalidUtf8,
            IoError,
            MissingFileName,
            MissingTemplateField,
            ParserError,
            StripPrefixError,
            TemplateNotFound,
        };

        match (self, other) {
            (&InvalidUtf8, &InvalidUtf8)                 => true,
            (&IoError(_), &IoError(_))                   => true,
            (&MissingFileName, &MissingFileName)         => true,
            (&MissingTemplateField, &MissingFileName)    => true,
            (&ParserError(ref a), &ParserError(ref b))   => a == b,
            (&StripPrefixError(_), &StripPrefixError(_)) => true,
            (&TemplateNotFound, &TemplateNotFound)       => true,
            _ => false,
        }
    }
}
<commit_msg>feat(error): implement `std::error::Error` for `Error`<commit_after>use std::error::Error as StdError;
use std::fmt;
use std::io::{self, ErrorKind};
use std::path::{self, Path};
use std::string;

use parser;

/// An enum of all error kinds.
#[derive(Debug)]
pub enum Error {
    /// An error for when a type cannot be parsed to a string because it
    /// contains invalid UTF-8.
    InvalidUtf8,
    /// An IO error was encountered.
    IoError(io::Error),
    /// An error which occurs when a path which is expected to contain a file
    /// name as the final component instead terminates in `.`, `..`, or solely
    /// of a root of prefix.
    MissingFileName,
    /// An error for when the template field is expected but not specified in a
    /// document header.
    MissingTemplateField,
    /// Wraps errors emitted by methods when attempting to parse a document.
    ParserError(parser::Error),
    /// Wraps errors emitted by the `Path::strip_prefix` method.
    StripPrefixError(path::StripPrefixError),
    /// An error which occurs when a specified template cannot be found.
    TemplateNotFound,
}

impl Error {
    /// Create an error for a non-directory path which was expected to be as
    /// directory.
    pub fn path_is_not_a_directory<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::InvalidInput, format!(
                    "specified path is not a directory: {}",
                    path.as_ref().display(),
                )))
    }

    /// Create an error for a path which unexpectedly points at a non-existing
    /// entity.
    pub fn path_not_found<P>(path: &P) -> Self
        where P: AsRef<Path> + fmt::Debug,
    {
        Error::IoError(io::Error::new(ErrorKind::NotFound, format!(
                    "specified path not found: {}",
                    path.as_ref().display(),
                )))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::IoError(ref e) => e.fmt(f),
            &Error::ParserError(ref e) => e.fmt(f),
            &Error::StripPrefixError(ref e) => e.fmt(f),
            e => write!(f, "{}", e.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidUtf8 => "a string is not valid UTF-8",
            Error::IoError(ref e) => e.description(),
            Error::MissingFileName => "a path is missing a file name",
            Error::MissingTemplateField => "missing template field in header",
            Error::ParserError(ref e) => e.description(),
            Error::StripPrefixError(ref e) => e.description(),
            Error::TemplateNotFound => "specified template could not be found",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::IoError(ref e) => e.cause(),
            Error::ParserError(ref e) => e.cause(),
            Error::StripPrefixError(ref e) => e.cause(),
            _ => None,
        }
    }
}

/// Application generic result type.
pub type Result<T> = ::std::result::Result<T, self::Error>;

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

impl From<parser::Error> for Error {
    fn from(error: parser::Error) -> Error {
        Error::ParserError(error)
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_error: string::FromUtf8Error) -> Error {
        Error::InvalidUtf8
    }
}

impl From<path::StripPrefixError> for Error {
    fn from(error: path::StripPrefixError) -> Error {
        Error::StripPrefixError(error)
    }
}

// Implement `PartialEq` manually, since `std::io::Error` does not implement it.
impl PartialEq<Error> for Error {
    fn eq(&self, other: &Error) -> bool {
        use self::Error::{
            InvalidUtf8,
            IoError,
            MissingFileName,
            MissingTemplateField,
            ParserError,
            StripPrefixError,
            TemplateNotFound,
        };

        match (self, other) {
            (&InvalidUtf8, &InvalidUtf8)                 => true,
            (&IoError(_), &IoError(_))                   => true,
            (&MissingFileName, &MissingFileName)         => true,
            (&MissingTemplateField, &MissingFileName)    => true,
            (&ParserError(ref a), &ParserError(ref b))   => a == b,
            (&StripPrefixError(_), &StripPrefixError(_)) => true,
            (&TemplateNotFound, &TemplateNotFound)       => true,
            _ => false,
        }
    }
}
<|endoftext|>


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

/// An enum for describing and handling various errors encountered while dealing with `clog`
/// building, or writing of changelogs.
#[derive(Debug)]
pub enum Error {
    /// Generated while parsing config files such .clog.toml
    ConfigParseErr,
    /// Generated if the config file is not in TOML format
    ConfigFormatErr,
    /// Generated if the OS cannot determine the current directory
    CurrentDirErr,
    /// Generated when unable to read the TOML config file (perhaps due to permissions, etc.)
    TomlReadErr,
    /// Generated when an unrecognized link-style value is used
    LinkStyleErr,
    /// Generated when a string cannot be parsed to a SemVer value
    SemVerErr,
    /// Generated when there are errors creating the output file or stream
    CreateFileErr,
    /// Generated when there are errors writing to the changelog output file
    WriteErr,
    /// Generic catch all I/O related error
    IoErr,
    /// Unknown, but fatal error (a catch all)
    UnknownErr
}

// Shamelessly taken and adopted from https://github.com/BurntSushi :)
impl Error {
    /// Return whether this was a fatal error or not.
    pub fn is_fatal(&self) -> bool {
        // For now all errors are fatal
        true
    }

    /// Print this error and immediately exit the program.
    ///
    /// If the error is non-fatal then the error is printed to stdout and the
    /// exit status will be `0`. Otherwise, when the error is fatal, the error
    /// is printed to stderr and the exit status will be `1`.
    pub fn exit(&self) -> ! {
        if self.is_fatal() {
            wlnerr!("{}", self);
            ::std::process::exit(1)
        } else {
            println!("{}", self);
            ::std::process::exit(0)
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConfigParseErr  => "clog: error parsing config file",
            Error::ConfigFormatErr => "clog: incorrect format for config file",
            Error::CurrentDirErr   => "clog: cannot get current directory",
            Error::TomlReadErr     => "clog: cannot read TOML config file",
            Error::LinkStyleErr    => "clog: unrecognized link-style field",
            Error::SemVerErr       => "clog: cannot parse SemVer version",
            Error::CreateFileErr   => "clog: cannot create output file",
            Error::WriteErr        => "clog: cannot write to output file or stream",
            Error::UnknownErr      => "clog: unknown fatal error",
            Error::IoErr           => "clog: fatal i/o error with output file"
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            _ => None
        }
    }
}
<commit_msg>refactor(Errors): uses better error formatting<commit_after>use std::error::Error as StdError;
use std::fmt;

/// An enum for describing and handling various errors encountered while dealing with `clog`
/// building, or writing of changelogs.
#[derive(Debug)]
pub enum Error {
    /// Generated while parsing config files such .clog.toml
    ConfigParseErr,
    /// Generated if the config file is not in TOML format
    ConfigFormatErr,
    /// Generated if the OS cannot determine the current directory
    CurrentDirErr,
    /// Generated when unable to read the TOML config file (perhaps due to permissions, etc.)
    TomlReadErr,
    /// Generated when an unrecognized link-style value is used
    LinkStyleErr,
    /// Generated when there are errors creating the output file or stream
    CreateFileErr,
    /// Generated when there are errors writing to the changelog output file
    WriteErr,
    /// Generic catch all I/O related error
    IoErr,
    /// Unknown, but fatal error (a catch all)
    UnknownErr
}

// Shamelessly taken and adopted from https://github.com/BurntSushi :)
impl Error {
    /// Return whether this was a fatal error or not.
    pub fn is_fatal(&self) -> bool {
        // For now all errors are fatal
        true
    }

    /// Print this error and immediately exit the program.
    ///
    /// If the error is non-fatal then the error is printed to stdout and the
    /// exit status will be `0`. Otherwise, when the error is fatal, the error
    /// is printed to stderr and the exit status will be `1`.
    pub fn exit(&self) -> ! {
        if self.is_fatal() {
            wlnerr!("{}", self);
            ::std::process::exit(1)
        } else {
            println!("{}", self);
            ::std::process::exit(0)
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConfigParseErr  => "error parsing config file",
            Error::ConfigFormatErr => "incorrect format for config file",
            Error::CurrentDirErr   => "cannot get current directory",
            Error::TomlReadErr     => "cannot read TOML config file",
            Error::LinkStyleErr    => "unrecognized link-style field",
            Error::CreateFileErr   => "cannot create output file",
            Error::WriteErr        => "cannot write to output file or stream",
            Error::UnknownErr      => "unknown fatal error",
            Error::IoErr           => "fatal i/o error with output file"
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            _ => None
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::fmt::{self, Error as FormatError};
use std::io::Error as IoError;
use std::num::ParseIntError;

#[cfg(feature = "gateway")]
use async_tungstenite::tungstenite::error::Error as TungsteniteError;
#[cfg(feature = "http")]
use reqwest::{header::InvalidHeaderValue, Error as ReqwestError};
use serde_json::Error as JsonError;
use tracing::instrument;

#[cfg(feature = "client")]
use crate::client::ClientError;
#[cfg(feature = "collector")]
use crate::collector::CollectorError;
#[cfg(feature = "gateway")]
use crate::gateway::GatewayError;
#[cfg(feature = "http")]
use crate::http::HttpError;
use crate::internal::prelude::*;
use crate::model::ModelError;

/// 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.
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 [`Self::Client`] and
/// [`Self::Gateway`] variants.
#[derive(Debug)]
#[non_exhaustive]
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),
    #[cfg(feature = "simd-json")]
    /// An error from the `simd_json` crate.
    SimdJson(simd_json::Error),

    /// An error from the [`model`] module.
    ///
    /// [`model`]: crate::model
    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".*
    ///
    /// [`GuildId::ban`]: crate::model::id::GuildId::ban
    /// [`Member::ban`]: crate::model::guild::Member::ban
    ExceededLimit(String, u32),
    /// The input is not in the specified range.
    /// Returned by [`GuildId::members`], [`Guild::members`] and [`PartialGuild::members`]
    ///
    /// (param_name, value, range_min, range_max)
    ///
    /// [`GuildId::members`]: crate::model::id::GuildId::members
    /// [`Guild::members`]: crate::model::guild::Guild::members
    /// [`PartialGuild::members`]: crate::model::guild::PartialGuild::members
    NotInRange(&'static str, u64, u64, u64),
    /// 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.
    Other(&'static str),
    /// An error from the [`url`] crate.
    Url(String),
    /// A [client] error.
    ///
    /// [client]: crate::client
    #[cfg(feature = "client")]
    Client(ClientError),
    /// A [collector] error.
    ///
    /// [collector]: crate::collector
    #[cfg(feature = "collector")]
    Collector(CollectorError),
    /// An error from the [`gateway`] module.
    ///
    /// [`gateway`]: crate::gateway
    #[cfg(feature = "gateway")]
    Gateway(GatewayError),
    /// An error from the [`http`] module.
    ///
    /// [`http`]: crate::http
    #[cfg(feature = "http")]
    Http(Box<HttpError>),
    /// An error from the `tungstenite` crate.
    #[cfg(feature = "gateway")]
    Tungstenite(TungsteniteError),
}

#[cfg(feature = "simd-json")]
impl From<simd_json::Error> for Error {
    fn from(e: simd_json::Error) -> Self {
        Error::SimdJson(e)
    }
}

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)
    }
}

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 = "gateway")]
impl From<TungsteniteError> for Error {
    fn from(e: TungsteniteError) -> Error {
        Error::Tungstenite(e)
    }
}

#[cfg(feature = "http")]
impl From<HttpError> for Error {
    fn from(e: HttpError) -> Error {
        Error::Http(Box::new(e))
    }
}

#[cfg(feature = "http")]
impl From<InvalidHeaderValue> for Error {
    fn from(e: InvalidHeaderValue) -> Error {
        HttpError::InvalidHeader(e).into()
    }
}

#[cfg(feature = "http")]
impl From<ReqwestError> for Error {
    fn from(e: ReqwestError) -> Error {
        HttpError::Request(e).into()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Decode(msg, _) | Error::Other(msg) => f.write_str(msg),
            Error::ExceededLimit(..) => f.write_str("Input exceeded a limit"),
            Error::NotInRange(..) => f.write_str("Input is not in the specified range"),
            Error::Format(inner) => fmt::Display::fmt(&inner, f),
            Error::Io(inner) => fmt::Display::fmt(&inner, f),
            Error::Json(inner) => fmt::Display::fmt(&inner, f),
            Error::Model(inner) => fmt::Display::fmt(&inner, f),
            Error::Num(inner) => fmt::Display::fmt(&inner, f),
            Error::Url(msg) => f.write_str(msg),
            #[cfg(feature = "simd-json")]
            Error::SimdJson(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "client")]
            Error::Client(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "collector")]
            Error::Collector(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "gateway")]
            Error::Gateway(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "http")]
            Error::Http(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "gateway")]
            Error::Tungstenite(inner) => fmt::Display::fmt(&inner, f),
        }
    }
}

impl StdError for Error {
    #[instrument]
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::Format(inner) => Some(inner),
            Error::Io(inner) => Some(inner),
            Error::Json(inner) => Some(inner),
            Error::Model(inner) => Some(inner),
            Error::Num(inner) => Some(inner),
            #[cfg(feature = "client")]
            Error::Client(inner) => Some(inner),
            #[cfg(feature = "collector")]
            Error::Collector(inner) => Some(inner),
            #[cfg(feature = "gateway")]
            Error::Gateway(inner) => Some(inner),
            #[cfg(feature = "http")]
            Error::Http(inner) => Some(inner),
            #[cfg(feature = "gateway")]
            Error::Tungstenite(inner) => Some(inner),
            _ => None,
        }
    }
}
<commit_msg>Remove the `Error::Num` enum variant (#1847)<commit_after>use std::error::Error as StdError;
use std::fmt::{self, Error as FormatError};
use std::io::Error as IoError;

#[cfg(feature = "gateway")]
use async_tungstenite::tungstenite::error::Error as TungsteniteError;
#[cfg(feature = "http")]
use reqwest::{header::InvalidHeaderValue, Error as ReqwestError};
use serde_json::Error as JsonError;
use tracing::instrument;

#[cfg(feature = "client")]
use crate::client::ClientError;
#[cfg(feature = "collector")]
use crate::collector::CollectorError;
#[cfg(feature = "gateway")]
use crate::gateway::GatewayError;
#[cfg(feature = "http")]
use crate::http::HttpError;
use crate::internal::prelude::*;
use crate::model::ModelError;

/// 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.
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 [`Self::Client`] and
/// [`Self::Gateway`] variants.
#[derive(Debug)]
#[non_exhaustive]
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),
    #[cfg(feature = "simd-json")]
    /// An error from the `simd_json` crate.
    SimdJson(simd_json::Error),
    /// An error from the [`model`] module.
    ///
    /// [`model`]: crate::model
    Model(ModelError),
    /// 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".*
    ///
    /// [`GuildId::ban`]: crate::model::id::GuildId::ban
    /// [`Member::ban`]: crate::model::guild::Member::ban
    ExceededLimit(String, u32),
    /// The input is not in the specified range.
    /// Returned by [`GuildId::members`], [`Guild::members`] and [`PartialGuild::members`]
    ///
    /// (param_name, value, range_min, range_max)
    ///
    /// [`GuildId::members`]: crate::model::id::GuildId::members
    /// [`Guild::members`]: crate::model::guild::Guild::members
    /// [`PartialGuild::members`]: crate::model::guild::PartialGuild::members
    NotInRange(&'static str, u64, u64, u64),
    /// 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.
    Other(&'static str),
    /// An error from the [`url`] crate.
    Url(String),
    /// A [client] error.
    ///
    /// [client]: crate::client
    #[cfg(feature = "client")]
    Client(ClientError),
    /// A [collector] error.
    ///
    /// [collector]: crate::collector
    #[cfg(feature = "collector")]
    Collector(CollectorError),
    /// An error from the [`gateway`] module.
    ///
    /// [`gateway`]: crate::gateway
    #[cfg(feature = "gateway")]
    Gateway(GatewayError),
    /// An error from the [`http`] module.
    ///
    /// [`http`]: crate::http
    #[cfg(feature = "http")]
    Http(Box<HttpError>),
    /// An error from the `tungstenite` crate.
    #[cfg(feature = "gateway")]
    Tungstenite(TungsteniteError),
}

#[cfg(feature = "simd-json")]
impl From<simd_json::Error> for Error {
    fn from(e: simd_json::Error) -> Self {
        Error::SimdJson(e)
    }
}

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)
    }
}

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<ModelError> for Error {
    fn from(e: ModelError) -> Error {
        Error::Model(e)
    }
}

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

#[cfg(feature = "http")]
impl From<HttpError> for Error {
    fn from(e: HttpError) -> Error {
        Error::Http(Box::new(e))
    }
}

#[cfg(feature = "http")]
impl From<InvalidHeaderValue> for Error {
    fn from(e: InvalidHeaderValue) -> Error {
        HttpError::InvalidHeader(e).into()
    }
}

#[cfg(feature = "http")]
impl From<ReqwestError> for Error {
    fn from(e: ReqwestError) -> Error {
        HttpError::Request(e).into()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Decode(msg, _) | Error::Other(msg) => f.write_str(msg),
            Error::ExceededLimit(..) => f.write_str("Input exceeded a limit"),
            Error::NotInRange(..) => f.write_str("Input is not in the specified range"),
            Error::Format(inner) => fmt::Display::fmt(&inner, f),
            Error::Io(inner) => fmt::Display::fmt(&inner, f),
            Error::Json(inner) => fmt::Display::fmt(&inner, f),
            Error::Model(inner) => fmt::Display::fmt(&inner, f),
            Error::Url(msg) => f.write_str(msg),
            #[cfg(feature = "simd-json")]
            Error::SimdJson(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "client")]
            Error::Client(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "collector")]
            Error::Collector(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "gateway")]
            Error::Gateway(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "http")]
            Error::Http(inner) => fmt::Display::fmt(&inner, f),
            #[cfg(feature = "gateway")]
            Error::Tungstenite(inner) => fmt::Display::fmt(&inner, f),
        }
    }
}

impl StdError for Error {
    #[instrument]
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::Format(inner) => Some(inner),
            Error::Io(inner) => Some(inner),
            Error::Json(inner) => Some(inner),
            Error::Model(inner) => Some(inner),
            #[cfg(feature = "client")]
            Error::Client(inner) => Some(inner),
            #[cfg(feature = "collector")]
            Error::Collector(inner) => Some(inner),
            #[cfg(feature = "gateway")]
            Error::Gateway(inner) => Some(inner),
            #[cfg(feature = "http")]
            Error::Http(inner) => Some(inner),
            #[cfg(feature = "gateway")]
            Error::Tungstenite(inner) => Some(inner),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.
//!
//! If you don't want to do this, you can write your own mainloop and
//! get the necessary event machinery by calling
//! `context.sdl_context.event_pump()` on your `Context`.  You can
//! then call whatever SDL event methods you want on that.  This is
//! not particularly elegant and is not guaranteed to be stable across
//! different versions of ggez (for instance, we may someday get rid of SDL2),
//! but trying to wrap it
//! up more conveniently really ends up with the exact same interface.
//!
//! TODO: UPDATE DOCS!
//!
//! See the `eventloop` example for an implementation.

use gilrs;
use winit;
use winit::dpi;

pub use input::keyboard::{KeyCode, KeyMods};
/// A mouse button.
pub use winit::MouseButton;

/// An analog axis of some device (controller, joystick...).
pub use gilrs::Axis;
/// A button of some device (controller, joystick...).
pub use gilrs::Button;

/// `winit` events; nested in a module for re-export neatness.
pub mod winit_event {
    pub use super::winit::{
        DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, MouseScrollDelta,
        TouchPhase, WindowEvent,
    };
}

use self::winit_event::*;
/// `winit` event loop.
pub use winit::EventsLoop;

use context::Context;
use GameResult;

/// A trait defining event callbacks; your primary interface with
/// `ggez`'s event loop.  Have a type implement this trait and
/// override at least the update() and draw() methods, then pass it to
/// `event::run()` to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// `key_down_event()`, which will by default exit the game if the escape
/// key is pressed.  Just override the methods you want to do things with.
pub trait EventHandler {
    /// Called upon each logic update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, _ctx: &mut Context) -> GameResult;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// `graphics::clear()` and end it with
    /// `graphics::present()` and `timer::yield_now()`
    fn draw(&mut self, _ctx: &mut Context) -> GameResult;

    /// A mouse button was pressed
    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// A mouse button was released
    fn mouse_button_up_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// The mouse was moved; it provides both absolute x and y coordinates in the window,
    /// and relative x and y coordinates compared to its last position.
    fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, _dx: f32, _dy: f32) {}

    /// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
    /// or horizontally (x, positive to the right and negative to the left).
    fn mouse_wheel_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32) {}

    /// A keyboard button was pressed.
    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        _keymods: KeyMods,
        _repeat: bool,
    ) {
        if keycode == KeyCode::Escape {
            super::quit(ctx);
        }
    }

    /// A keyboard button was released.
    fn key_up_event(&mut self, _ctx: &mut Context, _keycode: KeyCode, _keymods: KeyMods) {}

    /// A unicode character was received, usually from keyboard input.
    /// This is the intended way of facilitating text input.
    fn text_input_event(&mut self, _ctx: &mut Context, _character: char) {}

    /// A controller button was pressed; id identifies which controller.
    fn controller_button_down_event(&mut self, _ctx: &mut Context, _btn: Button, _id: usize) {}

    /// A controller button was released.
    fn controller_button_up_event(&mut self, _ctx: &mut Context, _btn: Button, _id: usize) {}

    /// A controller axis moved.
    fn controller_axis_event(&mut self, _ctx: &mut Context, _axis: Axis, _value: f32, _id: usize) {}

    /// Called when the window is shown or hidden.
    fn focus_event(&mut self, _ctx: &mut Context, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self, _ctx: &mut Context) -> bool {
        debug!("quit_event() callback called, quitting...");
        false
    }

    /// Called when the user resizes the window, or when it is resized
    /// via `graphics::set_mode()`.
    fn resize_event(&mut self, _ctx: &mut Context, _width: f32, _height: f32) {}
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the `timer` module for more info.
pub fn run<S>(ctx: &mut Context, events_loop: &mut EventsLoop, state: &mut S) -> GameResult
where
    S: EventHandler,
{
    use input::{keyboard, mouse};

    while ctx.continuing {
        ctx.timer_context.tick();
        events_loop.poll_events(|event| {
            let event = ctx.process_event(&event);
            match event {
                Event::WindowEvent { event, .. } => match event {
                    WindowEvent::Resized(dpi::LogicalSize { width, height }) => {
                        state.resize_event(ctx, width as f32, height as f32);
                    }
                    WindowEvent::CloseRequested => {
                        if !state.quit_event(ctx) {
                            super::quit(ctx);
                        }
                    }
                    WindowEvent::Focused(gained) => {
                        state.focus_event(ctx, gained);
                    }
                    WindowEvent::ReceivedCharacter(ch) => {
                        state.text_input_event(ctx, ch);
                    }
                    WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                state: ElementState::Pressed,
                                virtual_keycode: Some(keycode),
                                modifiers,
                                ..
                            },
                        ..
                    } => {
                        let repeat = keyboard::is_key_repeated(ctx);
                        state.key_down_event(ctx, keycode, modifiers.into(), repeat);
                    }
                    WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                state: ElementState::Released,
                                virtual_keycode: Some(keycode),
                                modifiers,
                                ..
                            },
                        ..
                    } => {
                        state.key_up_event(ctx, keycode, modifiers.into());
                    }
                    WindowEvent::MouseWheel { delta, .. } => {
                        let (x, y) = match delta {
                            MouseScrollDelta::LineDelta(x, y) => (x, y),
                            MouseScrollDelta::PixelDelta(dpi::LogicalPosition { x, y }) => {
                                (x as f32, y as f32)
                            }
                        };
                        state.mouse_wheel_event(ctx, x, y);
                    }
                    WindowEvent::MouseInput {
                        state: element_state,
                        button,
                        ..
                    } => {
                        let position = mouse::position(ctx);
                        match element_state {
                            ElementState::Pressed => {
                                state.mouse_button_down_event(ctx, button, position.x, position.y)
                            }
                            ElementState::Released => {
                                state.mouse_button_up_event(ctx, button, position.x, position.y)
                            }
                        }
                    }
                    WindowEvent::CursorMoved { .. } => {
                        let position = mouse::position(ctx);
                        let delta = mouse::delta(ctx);
                        state.mouse_motion_event(ctx, position.x, position.y, delta.x, delta.y);
                    }
                    x => {
                        trace!("ignoring window event {:?}", x);
                    }
                },
                Event::DeviceEvent { event, .. } => match event {
                    _ => (),
                },
                Event::Awakened => (),
                Event::Suspended(_) => (),
            }
        });
        while let Some(gilrs::Event { id, event, .. }) = ctx.gamepad_context.next_event() {
            match event {
                gilrs::EventType::ButtonPressed(button, _) => {
                    state.controller_button_down_event(ctx, button, id);
                }
                gilrs::EventType::ButtonReleased(button, _) => {
                    state.controller_button_up_event(ctx, button, id);
                }
                gilrs::EventType::AxisChanged(axis, value, _) => {
                    state.controller_axis_event(ctx, axis, value, id);
                }
                _ => {}
            }
        }
        state.update(ctx)?;
        state.draw(ctx)?;
    }

    Ok(())
}
<commit_msg>Only poll for gamepad events when the gamepad module is enabled<commit_after>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.
//!
//! If you don't want to do this, you can write your own mainloop and
//! get the necessary event machinery by calling
//! `context.sdl_context.event_pump()` on your `Context`.  You can
//! then call whatever SDL event methods you want on that.  This is
//! not particularly elegant and is not guaranteed to be stable across
//! different versions of ggez (for instance, we may someday get rid of SDL2),
//! but trying to wrap it
//! up more conveniently really ends up with the exact same interface.
//!
//! TODO: UPDATE DOCS!
//!
//! See the `eventloop` example for an implementation.

use gilrs;
use winit;
use winit::dpi;

pub use input::keyboard::{KeyCode, KeyMods};
/// A mouse button.
pub use winit::MouseButton;

/// An analog axis of some device (controller, joystick...).
pub use gilrs::Axis;
/// A button of some device (controller, joystick...).
pub use gilrs::Button;

/// `winit` events; nested in a module for re-export neatness.
pub mod winit_event {
    pub use super::winit::{
        DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, MouseScrollDelta,
        TouchPhase, WindowEvent,
    };
}

use self::winit_event::*;
/// `winit` event loop.
pub use winit::EventsLoop;

use context::Context;
use GameResult;

/// A trait defining event callbacks; your primary interface with
/// `ggez`'s event loop.  Have a type implement this trait and
/// override at least the update() and draw() methods, then pass it to
/// `event::run()` to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// `key_down_event()`, which will by default exit the game if the escape
/// key is pressed.  Just override the methods you want to do things with.
pub trait EventHandler {
    /// Called upon each logic update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, _ctx: &mut Context) -> GameResult;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// `graphics::clear()` and end it with
    /// `graphics::present()` and `timer::yield_now()`
    fn draw(&mut self, _ctx: &mut Context) -> GameResult;

    /// A mouse button was pressed
    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// A mouse button was released
    fn mouse_button_up_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// The mouse was moved; it provides both absolute x and y coordinates in the window,
    /// and relative x and y coordinates compared to its last position.
    fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, _dx: f32, _dy: f32) {}

    /// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
    /// or horizontally (x, positive to the right and negative to the left).
    fn mouse_wheel_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32) {}

    /// A keyboard button was pressed.
    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        _keymods: KeyMods,
        _repeat: bool,
    ) {
        if keycode == KeyCode::Escape {
            super::quit(ctx);
        }
    }

    /// A keyboard button was released.
    fn key_up_event(&mut self, _ctx: &mut Context, _keycode: KeyCode, _keymods: KeyMods) {}

    /// A unicode character was received, usually from keyboard input.
    /// This is the intended way of facilitating text input.
    fn text_input_event(&mut self, _ctx: &mut Context, _character: char) {}

    /// A controller button was pressed; id identifies which controller.
    fn controller_button_down_event(&mut self, _ctx: &mut Context, _btn: Button, _id: usize) {}

    /// A controller button was released.
    fn controller_button_up_event(&mut self, _ctx: &mut Context, _btn: Button, _id: usize) {}

    /// A controller axis moved.
    fn controller_axis_event(&mut self, _ctx: &mut Context, _axis: Axis, _value: f32, _id: usize) {}

    /// Called when the window is shown or hidden.
    fn focus_event(&mut self, _ctx: &mut Context, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self, _ctx: &mut Context) -> bool {
        debug!("quit_event() callback called, quitting...");
        false
    }

    /// Called when the user resizes the window, or when it is resized
    /// via `graphics::set_mode()`.
    fn resize_event(&mut self, _ctx: &mut Context, _width: f32, _height: f32) {}
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the `timer` module for more info.
pub fn run<S>(ctx: &mut Context, events_loop: &mut EventsLoop, state: &mut S) -> GameResult
where
    S: EventHandler,
{
    use input::{keyboard, mouse};

    while ctx.continuing {
        ctx.timer_context.tick();
        events_loop.poll_events(|event| {
            let event = ctx.process_event(&event);
            match event {
                Event::WindowEvent { event, .. } => match event {
                    WindowEvent::Resized(dpi::LogicalSize { width, height }) => {
                        state.resize_event(ctx, width as f32, height as f32);
                    }
                    WindowEvent::CloseRequested => {
                        if !state.quit_event(ctx) {
                            super::quit(ctx);
                        }
                    }
                    WindowEvent::Focused(gained) => {
                        state.focus_event(ctx, gained);
                    }
                    WindowEvent::ReceivedCharacter(ch) => {
                        state.text_input_event(ctx, ch);
                    }
                    WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                state: ElementState::Pressed,
                                virtual_keycode: Some(keycode),
                                modifiers,
                                ..
                            },
                        ..
                    } => {
                        let repeat = keyboard::is_key_repeated(ctx);
                        state.key_down_event(ctx, keycode, modifiers.into(), repeat);
                    }
                    WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                state: ElementState::Released,
                                virtual_keycode: Some(keycode),
                                modifiers,
                                ..
                            },
                        ..
                    } => {
                        state.key_up_event(ctx, keycode, modifiers.into());
                    }
                    WindowEvent::MouseWheel { delta, .. } => {
                        let (x, y) = match delta {
                            MouseScrollDelta::LineDelta(x, y) => (x, y),
                            MouseScrollDelta::PixelDelta(dpi::LogicalPosition { x, y }) => {
                                (x as f32, y as f32)
                            }
                        };
                        state.mouse_wheel_event(ctx, x, y);
                    }
                    WindowEvent::MouseInput {
                        state: element_state,
                        button,
                        ..
                    } => {
                        let position = mouse::position(ctx);
                        match element_state {
                            ElementState::Pressed => {
                                state.mouse_button_down_event(ctx, button, position.x, position.y)
                            }
                            ElementState::Released => {
                                state.mouse_button_up_event(ctx, button, position.x, position.y)
                            }
                        }
                    }
                    WindowEvent::CursorMoved { .. } => {
                        let position = mouse::position(ctx);
                        let delta = mouse::delta(ctx);
                        state.mouse_motion_event(ctx, position.x, position.y, delta.x, delta.y);
                    }
                    x => {
                        trace!("ignoring window event {:?}", x);
                    }
                },
                Event::DeviceEvent { event, .. } => match event {
                    _ => (),
                },
                Event::Awakened => (),
                Event::Suspended(_) => (),
            }
        });
        if ctx.conf.modules.gamepad {
            while let Some(gilrs::Event { id, event, .. }) = ctx.gamepad_context.next_event() {
                match event {
                    gilrs::EventType::ButtonPressed(button, _) => {
                        state.controller_button_down_event(ctx, button, id);
                    }
                    gilrs::EventType::ButtonReleased(button, _) => {
                        state.controller_button_up_event(ctx, button, id);
                    }
                    gilrs::EventType::AxisChanged(axis, value, _) => {
                        state.controller_axis_event(ctx, axis, value, id);
                    }
                    _ => {}
                }
            }
        }
        state.update(ctx)?;
        state.draw(ctx)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.

/// A key code.
pub use sdl2::keyboard::Keycode;

/// A struct that holds the state of modifier buttons such as ctrl or shift.
pub use sdl2::keyboard::Mod;
/// A mouse button press.
pub use sdl2::mouse::MouseButton;
/// A struct containing the mouse state at a given instant.
pub use sdl2::mouse::MouseState;

/// A controller button.
pub use sdl2::controller::Button;
/// A controller axis.
pub use sdl2::controller::Axis;

use sdl2::event::Event::*;
use sdl2::event;
use sdl2::mouse;
use sdl2::keyboard;

use context::Context;
use GameResult;
use timer;

use std::time::Duration;

/// A trait defining event callbacks; your primary interface with
/// `ggez`'s event loop.  Have a type implement this trait and
/// override at least the update() and draw() methods, then pass it to
/// `event::run()` to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// `key_down_event()`, which will by default exit the game if escape
/// is pressed.  Just override the methods you want to do things with.
pub trait EventHandler {
    /// Called upon each physics update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, ctx: &mut Context, dt: Duration) -> GameResult<()>;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// `graphics::clear()` and end it with
    /// `graphics::present()` and `timer::sleep_until_next_frame()`
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()>;

    fn mouse_button_down_event(&mut self, _button: mouse::MouseButton, _x: i32, _y: i32) {}

    fn mouse_button_up_event(&mut self, _button: mouse::MouseButton, _x: i32, _y: i32) {}

    fn mouse_motion_event(&mut self,
                          _state: mouse::MouseState,
                          _x: i32,
                          _y: i32,
                          _xrel: i32,
                          _yrel: i32) {
    }

    fn mouse_wheel_event(&mut self, _x: i32, _y: i32) {}

    fn key_down_event(&mut self, _keycode: Keycode, _keymod: Mod, _repeat: bool) {}

    fn key_up_event(&mut self, _keycode: Keycode, _keymod: Mod, _repeat: bool) {}

    fn controller_button_down_event(&mut self, _btn: Button, _instance_id: i32) {}
    fn controller_button_up_event(&mut self, _btn: Button, _instance_id: i32) {}
    fn controller_axis_event(&mut self, _axis: Axis, _value: i16, _instance_id: i32) {}

    fn focus_event(&mut self, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self) -> bool {
        println!("Quitting game");
        false
    }
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the `timer` module for more info.
pub fn run<S>(ctx: &mut Context, state: &mut S) -> GameResult<()>
    where S: EventHandler
{
    {
        let mut event_pump = ctx.sdl_context.event_pump()?;

        let mut continuing = true;
        while continuing {
            ctx.timer_context.tick();

            for event in event_pump.poll_iter() {
                match event {
                    Quit { .. } => {
                        continuing = state.quit_event();
                        // println!("Quit event: {:?}", t);
                    }
                    KeyDown {
                        keycode,
                        keymod,
                        repeat,
                        ..
                    } => {
                        if let Some(key) = keycode {
                            if key == keyboard::Keycode::Escape {
                                ctx.quit()?;
                            } else {
                                state.key_down_event(key, keymod, repeat)
                            }
                        }
                    }
                    KeyUp {
                        keycode,
                        keymod,
                        repeat,
                        ..
                    } => {
                        if let Some(key) = keycode {
                            state.key_up_event(key, keymod, repeat)
                        }
                    }
                    MouseButtonDown { mouse_btn, x, y, .. } => {
                        state.mouse_button_down_event(mouse_btn, x, y)
                    }
                    MouseButtonUp { mouse_btn, x, y, .. } => {
                        state.mouse_button_up_event(mouse_btn, x, y)
                    }
                    MouseMotion {
                        mousestate,
                        x,
                        y,
                        xrel,
                        yrel,
                        ..
                    } => state.mouse_motion_event(mousestate, x, y, xrel, yrel),
                    MouseWheel { x, y, .. } => state.mouse_wheel_event(x, y),
                    ControllerButtonDown { button, which, .. } => {
                        state.controller_button_down_event(button, which)
                    }
                    ControllerButtonUp { button, which, .. } =>
                        state.controller_button_up_event(button, which),
                    ControllerAxisMotion { axis, value, which, .. } => {
                        state.controller_axis_event(axis, value, which)
                    }
                    Window { win_event: event::WindowEvent::FocusGained, .. } => {
                        state.focus_event(true)
                    }
                    Window { win_event: event::WindowEvent::FocusLost, .. } => {
                        state.focus_event(false)
                    }
                    _ => {}
                }
            }

            let dt = timer::get_delta(ctx);
            state.update(ctx, dt)?;
            state.draw(ctx)?;
        }
    }

    Ok(())
}
<commit_msg>Added window resize event callback.<commit_after>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.

/// A key code.
pub use sdl2::keyboard::Keycode;

/// A struct that holds the state of modifier buttons such as ctrl or shift.
pub use sdl2::keyboard::Mod;
/// A mouse button press.
pub use sdl2::mouse::MouseButton;
/// A struct containing the mouse state at a given instant.
pub use sdl2::mouse::MouseState;

/// A controller button.
pub use sdl2::controller::Button;
/// A controller axis.
pub use sdl2::controller::Axis;

use sdl2::event::Event::*;
use sdl2::event;
use sdl2::mouse;
use sdl2::keyboard;

use context::Context;
use GameResult;
use timer;

use std::time::Duration;

/// A trait defining event callbacks; your primary interface with
/// `ggez`'s event loop.  Have a type implement this trait and
/// override at least the update() and draw() methods, then pass it to
/// `event::run()` to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// `key_down_event()`, which will by default exit the game if escape
/// is pressed.  Just override the methods you want to do things with.
pub trait EventHandler {
    /// Called upon each physics update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, ctx: &mut Context, dt: Duration) -> GameResult<()>;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// `graphics::clear()` and end it with
    /// `graphics::present()` and `timer::sleep_until_next_frame()`
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()>;

    fn mouse_button_down_event(&mut self, _button: mouse::MouseButton, _x: i32, _y: i32) {}

    fn mouse_button_up_event(&mut self, _button: mouse::MouseButton, _x: i32, _y: i32) {}

    fn mouse_motion_event(&mut self,
                          _state: mouse::MouseState,
                          _x: i32,
                          _y: i32,
                          _xrel: i32,
                          _yrel: i32) {
    }

    fn mouse_wheel_event(&mut self, _x: i32, _y: i32) {}

    fn key_down_event(&mut self, _keycode: Keycode, _keymod: Mod, _repeat: bool) {}

    fn key_up_event(&mut self, _keycode: Keycode, _keymod: Mod, _repeat: bool) {}

    fn controller_button_down_event(&mut self, _btn: Button, _instance_id: i32) {}
    fn controller_button_up_event(&mut self, _btn: Button, _instance_id: i32) {}
    fn controller_axis_event(&mut self, _axis: Axis, _value: i16, _instance_id: i32) {}

    fn focus_event(&mut self, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self) -> bool {
        println!("Quitting game");
        false
    }

    /// Called when the user resizes the window.
    /// Is not called when you resize it yourself with
    /// `graphics::set_mode()` though.
    fn resize_event(&mut self, _ctx: &mut Context, _width: u32, _height: u32) {}
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the `timer` module for more info.
pub fn run<S>(ctx: &mut Context, state: &mut S) -> GameResult<()>
    where S: EventHandler
{
    {
        let mut event_pump = ctx.sdl_context.event_pump()?;

        let mut continuing = true;
        while continuing {
            ctx.timer_context.tick();

            for event in event_pump.poll_iter() {
                match event {
                    Quit { .. } => {
                        continuing = state.quit_event();
                        // println!("Quit event: {:?}", t);
                    }
                    KeyDown {
                        keycode,
                        keymod,
                        repeat,
                        ..
                    } => {
                        if let Some(key) = keycode {
                            if key == keyboard::Keycode::Escape {
                                ctx.quit()?;
                            } else {
                                state.key_down_event(key, keymod, repeat)
                            }
                        }
                    }
                    KeyUp {
                        keycode,
                        keymod,
                        repeat,
                        ..
                    } => {
                        if let Some(key) = keycode {
                            state.key_up_event(key, keymod, repeat)
                        }
                    }
                    MouseButtonDown { mouse_btn, x, y, .. } => {
                        state.mouse_button_down_event(mouse_btn, x, y)
                    }
                    MouseButtonUp { mouse_btn, x, y, .. } => {
                        state.mouse_button_up_event(mouse_btn, x, y)
                    }
                    MouseMotion {
                        mousestate,
                        x,
                        y,
                        xrel,
                        yrel,
                        ..
                    } => state.mouse_motion_event(mousestate, x, y, xrel, yrel),
                    MouseWheel { x, y, .. } => state.mouse_wheel_event(x, y),
                    ControllerButtonDown { button, which, .. } => {
                        state.controller_button_down_event(button, which)
                    }
                    ControllerButtonUp { button, which, .. } =>
                        state.controller_button_up_event(button, which),
                    ControllerAxisMotion { axis, value, which, .. } => {
                        state.controller_axis_event(axis, value, which)
                    }
                    Window { win_event: event::WindowEvent::FocusGained, .. } => {
                        state.focus_event(true)
                    }
                    Window { win_event: event::WindowEvent::FocusLost, .. } => {
                        state.focus_event(false)
                    }
                    Window { win_event: event::WindowEvent::Resized(w,h), .. } => {
                        state.resize_event(ctx, w as u32, h as u32);
                    }
                    _ => {}
                }
            }

            let dt = timer::get_delta(ctx);
            state.update(ctx, dt)?;
            state.draw(ctx)?;
        }
    }

    Ok(())
}
<|endoftext|>