nbt/
error.rs

1use std::error::Error as StdError;
2use std::fmt;
3use std::io;
4use std::io::ErrorKind::InvalidInput;
5use std::result::Result as StdResult;
6
7#[cfg(feature = "serde")]
8use serde;
9
10/// A convenient alias type for results when reading/writing the Named Binary
11/// Tag format.
12pub type Result<T> = StdResult<T, Error>;
13
14/// Errors that may be encountered when constructing, parsing, or encoding
15/// `NbtValue` and `NbtBlob` objects.
16///
17/// `Error`s can be seamlessly converted to more general `io::Error` objects
18/// using `std::convert::From::from()`.
19#[derive(Debug)]
20pub enum Error {
21    /// Wraps errors emitted by methods during I/O operations.
22    IoError(io::Error),
23    /// Wraps errors emitted during (de-)serialization with `serde`.
24    #[cfg(feature = "serde")]
25    Serde(String),
26    /// An error for when an unknown type ID is encountered in decoding NBT
27    /// binary representations. Includes the ID in question.
28    InvalidTypeId(i8),
29    /// An error emitted when trying to create `NbtBlob`s with incorrect lists.
30    HeterogeneousList,
31    /// An error for when NBT binary representations do not begin with an
32    /// `NbtValue::Compound`.
33    NoRootCompound,
34    /// An error for when NBT binary representations contain invalid UTF-8
35    /// strings.
36    InvalidUtf8,
37    /// An error for when NBT binary representations are missing end tags,
38    /// contain fewer bytes than advertised, or are otherwise incomplete.
39    IncompleteNbtValue,
40    /// An error encountered when parsing NBT binary representations, where
41    /// deserialization encounters a different tag than expected.
42    TagMismatch(i8, i8),
43    /// An error encountered when parsing NBT binary representations, where
44    /// deserialization encounters a field name it is not expecting.
45    UnexpectedField(String),
46    /// An error encountered when deserializing a boolean from an invalid byte.
47    NonBooleanByte(i8),
48    /// An error encountered when serializing a Rust type with no meaningful NBT
49    /// representation.
50    UnrepresentableType(&'static str),
51    /// An error encountered when trying to (de)serialize a map key with a
52    /// non-string type.
53    NonStringMapKey,
54}
55
56impl fmt::Display for Error {
57    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58        match self {
59            &Error::IoError(ref e)     => e.fmt(f),
60            #[cfg(feature = "serde")]
61            &Error::Serde(ref msg)     => write!(f, "{}", msg),
62            &Error::InvalidTypeId(t)   => write!(f, "invalid NBT tag byte: '{}'", t),
63            &Error::TagMismatch(a, b)  => write!(f, "encountered NBT tag '{}' but expected '{}'", a, b),
64            &Error::NonBooleanByte(b)  => write!(f, "encountered a byte value '{}' inside a boolean", b),
65            &Error::UnexpectedField(ref name) => write!(f, "encountered an unexpected field '{}'", name),
66            &Error::UnrepresentableType(ref name) => write!(f, "encountered type '{}', which has no meaningful NBT representation", name),
67            // Static messages should suffice for the remaining errors.
68            other => write!(f, "{}", other.description()),
69        }
70    }
71}
72
73impl StdError for Error {
74    fn description(&self) -> &str {
75        match *self {
76            Error::IoError(ref e)     => e.description(),
77            #[cfg(feature = "serde")]
78            Error::Serde(ref msg)     => &msg[..],
79            Error::InvalidTypeId(_)   => "invalid NBT tag byte",
80            Error::HeterogeneousList  => "values in NBT Lists must be homogeneous",
81            Error::NoRootCompound     => "the root value must be Compound-like (tag = 0x0a)",
82            Error::InvalidUtf8        => "a string is not valid UTF-8",
83            Error::IncompleteNbtValue => "data does not represent a complete NbtValue",
84            Error::NonStringMapKey    => "encountered a non-string map key",
85            Error::TagMismatch(_, _)  => "encountered one NBT tag but expected another",
86            Error::UnexpectedField(_) => "encountered an unexpected field",
87            Error::NonBooleanByte(_)  => "encountered a non-boolean byte value inside a boolean",
88            Error::UnrepresentableType(_) => "encountered a type with no meaningful NBT representation",
89        }
90    }
91
92    // Deprecated in 1.33 in favour of source(), added in 1.30. This is recent
93    // enough that we should attempt to support older compilers, especially
94    // since we're on the 2015 edition at this time.
95    #[allow(deprecated)]
96    fn cause(&self) -> Option<&dyn StdError> {
97        match *self {
98            Error::IoError(ref e) => e.cause(),
99            _ => None
100        }
101    }
102}
103
104// Implement PartialEq manually, since std::io::Error is not PartialEq.
105impl PartialEq<Error> for Error {
106    fn eq(&self, other: &Error) -> bool {
107        use Error::{IoError, InvalidTypeId, HeterogeneousList, NoRootCompound,
108                    InvalidUtf8, IncompleteNbtValue, TagMismatch, UnexpectedField, NonBooleanByte,
109                    UnrepresentableType};
110
111        match (self, other) {
112            (&IoError(_), &IoError(_))                 => true,
113            #[cfg(feature = "serde")]
114            (&Error::Serde(_), &Error::Serde(_))       => true,
115            (&InvalidTypeId(a), &InvalidTypeId(b))     => a == b,
116            (&HeterogeneousList, &HeterogeneousList)   => true,
117            (&NoRootCompound, &NoRootCompound)         => true,
118            (&InvalidUtf8, &InvalidUtf8)               => true,
119            (&IncompleteNbtValue, &IncompleteNbtValue) => true,
120            (&TagMismatch(a, b), &TagMismatch(c, d))   => a == c && b == d,
121            (&UnexpectedField(ref a), &UnexpectedField(ref b)) => a == b,
122            (&NonBooleanByte(a), &NonBooleanByte(b))   => a == b,
123            (&UnrepresentableType(ref a), &UnrepresentableType(ref b)) => a == b,
124            _ => false
125        }
126    }
127}
128
129impl From<io::Error> for Error {
130    fn from(e: io::Error) -> Error {
131        use std::io::ErrorKind;
132
133        if e.kind() == ErrorKind::UnexpectedEof {
134            return Error::IncompleteNbtValue;
135        }
136        Error::IoError(e)
137    }
138}
139
140impl From<cesu8::Cesu8DecodingError> for Error {
141    fn from(_: cesu8::Cesu8DecodingError) -> Error {
142        Error::InvalidUtf8
143    }
144}
145
146impl From<Error> for io::Error {
147    fn from(e: Error) -> io::Error {
148        match e {
149            Error::IoError(e) => e,
150            Error::InvalidTypeId(id) =>
151                io::Error::new(InvalidInput, &format!("invalid NBT tag byte: {}", id)[..]),
152            Error::TagMismatch(a, b) =>
153                io::Error::new(InvalidInput, &format!("encountered NBT tag {} \
154                                                       but expected {}", a, b)[..]),
155            Error::UnexpectedField(f) =>
156                io::Error::new(InvalidInput, &format!("encountered unexpected field \
157                                                       with name {}", f)[..]),
158            other => io::Error::new(InvalidInput, other.description()),
159        }
160    }
161}
162
163#[cfg(feature = "serde")]
164impl serde::ser::Error for Error {
165    fn custom<T: fmt::Display>(msg: T) -> Error {
166        Error::Serde(msg.to_string())
167    }
168}
169
170#[cfg(feature = "serde")]
171impl serde::de::Error for Error {
172    fn custom<T: fmt::Display>(msg: T) -> Error {
173        Error::Serde(msg.to_string())
174    }
175}