1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Functions and types relating to error handling.


use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::path::PathBuf;
use std::result;

use image::ImageError;

#[cfg(feature = "audio")]
use rodio::decoder::DecoderError;

/// A specialized `Result` type for Tetra.

///

/// All Tetra functions with a recoverable failure condition will return this type.

/// In your game code, you can either use it directly, or wrap it in your own error type.

pub type Result<T = ()> = result::Result<T, TetraError>;

/// The types of error that can occur in a Tetra game.

#[non_exhaustive]
#[derive(Debug)]
pub enum TetraError {
    /// Returned when the underlying platform returns an unexpected error.

    /// This usually isn't something your game can reasonably be expected to recover from.

    PlatformError(String),

    /// Returned when your game fails to load an asset. This is usually caused by an

    /// incorrect file path, or some form of permission issues.

    FailedToLoadAsset {
        /// The underlying reason for the error.

        reason: io::Error,

        /// The path to the asset that failed to load.

        path: PathBuf,
    },

    /// Returned when a color is invalid.

    InvalidColor,

    /// Returned when a texture's data is invalid.

    InvalidTexture(ImageError),

    /// Returned when a shader fails to compile.

    InvalidShader(String),

    /// Returned when a font could not be read.

    InvalidFont,

    /// Returned when a sound cannot be decoded.

    #[cfg(feature = "audio")]
    InvalidSound(DecoderError),

    /// Returned when not enough data is provided to fill a buffer.

    /// This may happen if you're creating a texture from raw data and you don't provide

    /// enough data.

    NotEnoughData {
        /// The number of bytes that were expected.

        expected: usize,

        /// The number of bytes that were provided.

        actual: usize,
    },

    /// Returned when trying to play back audio without an available device.

    NoAudioDevice,

    /// Returned when your game tried to change the display settings (e.g. fullscreen, vsync)

    /// but was unable to do so.

    FailedToChangeDisplayMode(String),
}

impl Display for TetraError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            TetraError::PlatformError(reason) => {
                write!(f, "An error was thrown by the platform: {}", reason)
            }
            TetraError::FailedToLoadAsset { reason, path } => write!(
                f,
                "Failed to load asset from {}: {}",
                path.to_string_lossy(),
                reason
            ),
            TetraError::InvalidColor => write!(f, "Invalid color"),
            TetraError::InvalidTexture(reason) => write!(f, "Invalid texture: {}", reason),
            TetraError::InvalidShader(reason) => write!(f, "Invalid shader: {}", reason),
            TetraError::InvalidFont => write!(f, "Invalid font"),
            #[cfg(feature = "audio")]
            TetraError::InvalidSound(reason) => write!(f, "Invalid sound: {}", reason),
            TetraError::NotEnoughData { expected, actual } => write!(
                f,
                "Not enough data was provided to fill a buffer - expected {}, found {}.",
                expected, actual
            ),
            TetraError::FailedToChangeDisplayMode(reason) => {
                write!(f, "Failed to change display mode: {}", reason)
            }
            TetraError::NoAudioDevice => write!(f, "No audio device was available for playback."),
        }
    }
}

impl Error for TetraError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            TetraError::PlatformError(_) => None,
            TetraError::FailedToLoadAsset { reason, .. } => Some(reason),
            TetraError::InvalidColor => None,
            TetraError::InvalidTexture(reason) => Some(reason),
            TetraError::InvalidShader(_) => None,
            TetraError::InvalidFont => None,
            #[cfg(feature = "audio")]
            TetraError::InvalidSound(reason) => Some(reason),
            TetraError::NotEnoughData { .. } => None,
            TetraError::NoAudioDevice => None,
            TetraError::FailedToChangeDisplayMode(_) => None,
        }
    }
}