Skip to main content

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(u8),
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(u8, u8),
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::HeterogeneousList => write!(f, "values in NBT Lists must be homogeneous"),
64            Error::NoRootCompound => write!(f, "the root value must be Compound-like (tag = 0x0a)"),
65            Error::InvalidUtf8 => write!(f, "a string is not valid UTF-8"),
66            Error::IncompleteNbtValue => write!(f, "data does not represent a complete NbtValue"),
67            &Error::TagMismatch(a, b) => {
68                write!(f, "encountered NBT tag '{}' but expected '{}'", a, b)
69            }
70            &Error::NonBooleanByte(b) => {
71                write!(f, "encountered a byte value '{}' inside a boolean", b)
72            }
73            &Error::UnexpectedField(ref name) => {
74                write!(f, "encountered an unexpected field '{}'", name)
75            }
76            &Error::UnrepresentableType(ref name) => write!(
77                f,
78                "encountered type '{}', which has no meaningful NBT representation",
79                name
80            ),
81            Error::NonStringMapKey => write!(f, "encountered a non-string map key"),
82        }
83    }
84}
85
86impl StdError for Error {
87    fn source(&self) -> Option<&(dyn StdError + 'static)> {
88        match *self {
89            Error::IoError(ref e) => e.source(),
90            _ => None,
91        }
92    }
93}
94
95// Implement PartialEq manually, since std::io::Error is not PartialEq.
96impl PartialEq<Error> for Error {
97    fn eq(&self, other: &Error) -> bool {
98        use Error::{
99            HeterogeneousList, IncompleteNbtValue, InvalidTypeId, InvalidUtf8, IoError,
100            NoRootCompound, NonBooleanByte, TagMismatch, UnexpectedField, UnrepresentableType,
101        };
102
103        match (self, other) {
104            (&IoError(_), &IoError(_)) => true,
105            #[cfg(feature = "serde")]
106            (&Error::Serde(_), &Error::Serde(_)) => true,
107            (&InvalidTypeId(a), &InvalidTypeId(b)) => a == b,
108            (&HeterogeneousList, &HeterogeneousList) => true,
109            (&NoRootCompound, &NoRootCompound) => true,
110            (&InvalidUtf8, &InvalidUtf8) => true,
111            (&IncompleteNbtValue, &IncompleteNbtValue) => true,
112            (&TagMismatch(a, b), &TagMismatch(c, d)) => a == c && b == d,
113            (&UnexpectedField(ref a), &UnexpectedField(ref b)) => a == b,
114            (&NonBooleanByte(a), &NonBooleanByte(b)) => a == b,
115            (&UnrepresentableType(ref a), &UnrepresentableType(ref b)) => a == b,
116            _ => false,
117        }
118    }
119}
120
121impl From<io::Error> for Error {
122    fn from(e: io::Error) -> Error {
123        use std::io::ErrorKind;
124
125        if e.kind() == ErrorKind::UnexpectedEof {
126            return Error::IncompleteNbtValue;
127        }
128        Error::IoError(e)
129    }
130}
131
132impl From<cesu8::Cesu8DecodingError> for Error {
133    fn from(_: cesu8::Cesu8DecodingError) -> Error {
134        Error::InvalidUtf8
135    }
136}
137
138impl From<Error> for io::Error {
139    fn from(e: Error) -> io::Error {
140        match e {
141            Error::IoError(e) => e,
142            other => io::Error::new(InvalidInput, other),
143        }
144    }
145}
146
147#[cfg(feature = "serde")]
148impl serde::ser::Error for Error {
149    fn custom<T: fmt::Display>(msg: T) -> Error {
150        Error::Serde(msg.to_string())
151    }
152}
153
154#[cfg(feature = "serde")]
155impl serde::de::Error for Error {
156    fn custom<T: fmt::Display>(msg: T) -> Error {
157        Error::Serde(msg.to_string())
158    }
159}