1use serde::{de,ser};
28use std::{
29 fmt::{Display, self}, io, iter::FusedIterator
30};
31
32pub mod bin;
34
35mod tag;
36pub use tag::{Tag, Compound, List, TagConversionError, CompoundTryGetInto, byte_array, int_array, long_array};
37pub(crate) use tag::{ARRAY_ENUM_NAME, BYTE_ARRAY_NAME, INT_ARRAY_NAME, LONG_ARRAY_NAME};
38
39#[derive(Clone, PartialEq, Debug, Copy)]
41pub enum TagType {
42 End,
43 Byte,
44 Short,
45 Int,
46 Long,
47 Float,
48 Double,
49 ByteArray,
50 String,
51 List,
52 Compound,
53 IntArray,
54 LongArray,
55}
56
57impl TagType {
58 pub fn from_u8(id: u8) -> Result<TagType> {
60 match id {
61 0x00 => Ok(TagType::End),
62 0x01 => Ok(TagType::Byte),
63 0x02 => Ok(TagType::Short),
64 0x03 => Ok(TagType::Int),
65 0x04 => Ok(TagType::Long),
66 0x05 => Ok(TagType::Float),
67 0x06 => Ok(TagType::Double),
68 0x07 => Ok(TagType::ByteArray),
69 0x08 => Ok(TagType::String),
70 0x09 => Ok(TagType::List),
71 0x0A => Ok(TagType::Compound),
72 0x0B => Ok(TagType::IntArray),
73 0x0C => Ok(TagType::LongArray),
74 _ => Err(Error::new_owned(
75 format!("{} is an invalid NBT tag id", id)
76 )),
77 }
78 }
79}
80
81impl Display for TagType {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 match &self {
84 TagType::End => write!(f, "TAG_End"),
85 TagType::Byte => write!(f, "TAG_Byte"),
86 TagType::Short => write!(f, "TAG_Short"),
87 TagType::Int => write!(f, "TAG_Int"),
88 TagType::Long => write!(f, "TAG_Long"),
89 TagType::Float => write!(f, "TAG_Float"),
90 TagType::Double => write!(f, "TAG_Double"),
91 TagType::ByteArray => write!(f, "TAG_Byte_Array"),
92 TagType::String => write!(f, "TAG_String"),
93 TagType::List => write!(f, "TAG_List"),
94 TagType::Compound => write!(f, "TAG_Compound"),
95 TagType::IntArray => write!(f, "TAG_Int_Array"),
96 TagType::LongArray => write!(f, "TAG_Long_Array")
97 }
98 }
99}
100
101pub type Result<T> = std::result::Result<T, Error>;
102
103#[derive(Debug)]
106pub struct Error {
107 inner: Box<ErrorInner>,
110}
111
112#[derive(Debug)]
113struct ErrorInner {
114 trace: Vec<String>,
115 cause: Cause,
116}
117
118#[derive(Debug)]
119enum Cause {
120 Io(io::Error),
121 Mutf8(mutf8::Error),
122 Owned(Box<str>),
124 Static(&'static str),
125}
126
127impl Error {
128 pub(crate) fn new_owned(msg: impl Into<Box<str>>) -> Self {
129 Self {
130 inner: Box::new(ErrorInner {
131 trace: Vec::new(),
132 cause: Cause::Owned(msg.into()),
133 }),
134 }
135 }
136
137 pub(crate) fn new_static(msg: &'static str) -> Self {
138 Self {
139 inner: Box::new(ErrorInner {
140 trace: Vec::new(),
141 cause: Cause::Static(msg),
142 }),
143 }
144 }
145
146 pub(crate) fn field(mut self, ctx: impl Into<String>) -> Self {
147 self.inner.trace.push(ctx.into());
148 self
149 }
150
151 pub fn trace(
156 &self,
157 ) -> impl DoubleEndedIterator<Item = &str> + ExactSizeIterator + FusedIterator + Clone + '_
158 {
159 self.inner.trace.iter().rev().map(|s| s.as_str())
160 }
161}
162
163impl Display for Error {
164 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165 let len = self.inner.trace.len();
166
167 if len > 0 {
168 write!(f, "(")?;
169 for (i, ctx) in self.trace().enumerate() {
170 write!(f, "{ctx}")?;
171
172 if i != len - 1 {
173 write!(f, " → ")?;
174 }
175 }
176 write!(f, ") ")?;
177 }
178
179 match &self.inner.cause {
180 Cause::Io(e) => e.fmt(f),
181 Cause::Mutf8(e) => e.fmt(f),
182 Cause::Owned(s) => write!(f, "{s}"),
183 Cause::Static(s) => write!(f, "{s}"),
184 }
185 }
186}
187
188impl std::error::Error for Error {
189 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
190 match &self.inner.cause {
191 Cause::Io(e) => Some(e),
192 Cause::Mutf8(e) => Some(e),
193 Cause::Owned(_) => None,
194 Cause::Static(_) => None,
195 }
196 }
197}
198
199impl ser::Error for Error {
200 fn custom<T>(msg: T) -> Self
201 where
202 T: Display,
203 {
204 Error::new_owned(format!("{msg}"))
205 }
206}
207
208impl de::Error for Error {
209 fn custom<T>(msg: T) -> Self
210 where
211 T: Display,
212 {
213 Error::new_owned(format!("{msg}"))
214 }
215}
216
217impl From<io::Error> for Error {
218 fn from(e: io::Error) -> Self {
219 Self {
220 inner: Box::new(ErrorInner {
221 trace: Vec::new(),
222 cause: Cause::Io(e),
223 }),
224 }
225 }
226}
227
228impl From<mutf8::Error> for Error {
229 fn from(e: mutf8::Error) -> Self {
230 Self {
231 inner: Box::new(ErrorInner {
232 trace: Vec::new(),
233 cause: Cause::Mutf8(e),
234 }),
235 }
236 }
237}