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
121
122
123
124
125
126
127
128
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

use crate::prelude::*;
use core::ops::Deref;
use std::any::TypeId;
use std::fmt;

#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
    /// The data provider does not support the requested category.
    UnsupportedCategory(ResourceCategory),

    /// The data provider supports the category, but not the key (sub-category or version).
    UnsupportedResourceKey(ResourceKey),

    /// The data provider supports the key, but does not have data for the specific entry.
    UnavailableResourceOptions(DataRequest),

    /// The data provider supports the key, but it requires a language identifier, which was
    /// missing from the request.
    NeedsLanguageIdentifier(DataRequest),

    /// The operation cannot be completed without more type information. For example, data
    /// cannot be deserialized without the concrete type.
    NeedsTypeInfo,

    /// The payload is missing. This error is usually unexpected.
    MissingPayload,

    /// The TypeID of the payload does not match the expected TypeID.
    MismatchedType {
        /// The actual TypeID of the payload, if available.
        actual: Option<TypeId>,

        /// The expected TypeID derived from the generic type parameter at the call site.
        generic: Option<TypeId>,
    },

    /// An error occured during serialization or deserialization.
    #[cfg(feature = "erased-serde")]
    Serde(erased_serde::Error),

    /// The data provider encountered some other error when loading the resource, such as I/O.
    Resource(Box<dyn std::error::Error>),
}

impl From<&ResourceKey> for Error {
    fn from(resc_key: &ResourceKey) -> Self {
        Self::UnsupportedResourceKey(*resc_key)
    }
}

impl From<&ResourceCategory> for Error {
    fn from(category: &ResourceCategory) -> Self {
        Self::UnsupportedCategory(*category)
    }
}

impl From<DataRequest> for Error {
    fn from(req: DataRequest) -> Self {
        Self::UnavailableResourceOptions(req)
    }
}

#[cfg(feature = "erased-serde")]
impl From<erased_serde::Error> for Error {
    fn from(err: erased_serde::Error) -> Self {
        Self::Serde(err)
    }
}

impl From<Box<dyn std::error::Error>> for Error {
    fn from(err: Box<dyn std::error::Error>) -> Self {
        Self::Resource(err)
    }
}

impl Error {
    pub fn new_resc_error<T>(err: T) -> Self
    where
        T: 'static + std::error::Error,
    {
        Self::Resource(Box::new(err))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::UnsupportedCategory(category) => write!(f, "Unsupported category: {}", category),
            Self::UnsupportedResourceKey(resc_key) => {
                write!(f, "Unsupported resource key: {}", resc_key)
            }
            Self::UnavailableResourceOptions(request) => {
                write!(f, "Unavailable resource options: {}", request)
            }
            Self::NeedsLanguageIdentifier(request) => write!(
                f,
                "Requested key needs language identifier in request: {}",
                request
            ),
            Self::NeedsTypeInfo => write!(f, "Complete type information is required"),
            Self::MissingPayload => write!(f, "Payload is missing"),
            Self::MismatchedType { actual, generic } => {
                write!(f, "Mismatched type: payload is {:?}", actual)?;
                if let Some(type_id) = generic {
                    write!(f, " (expected from generic type parameter: {:?})", type_id)?;
                }
                Ok(())
            }
            #[cfg(feature = "erased-serde")]
            Self::Serde(err) => write!(f, "Serde error: {}", err),
            Self::Resource(err) => write!(f, "Failed to load resource: {}", err),
        }
    }
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::Resource(error) => Some(error.deref()),
            _ => None,
        }
    }
}