1use std::{collections::HashMap, fmt::Display, hash::Hash, str::FromStr};
2
3use crate::DeserializeError;
4
5pub trait Deserialize: Sized {
6 fn from_nbt(nbt: &crate::borrow::BaseNbt) -> Result<Self, DeserializeError> {
7 Self::from_compound(nbt.as_compound())
8 }
9
10 fn from_compound(compound: crate::borrow::NbtCompound) -> Result<Self, DeserializeError>;
11}
12
13pub trait Serialize: Sized {
14 fn to_nbt(self) -> crate::owned::BaseNbt {
15 crate::owned::BaseNbt::new("", self.to_compound())
16 }
17
18 fn to_compound(self) -> crate::owned::NbtCompound;
19}
20
21pub trait FromNbtTag: Sized {
22 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self>;
23 fn from_optional_nbt_tag(
24 tag: Option<crate::borrow::NbtTag>,
25 ) -> Result<Option<Self>, DeserializeError> {
26 match tag {
27 Some(tag) => Ok(Self::from_nbt_tag(tag)),
28 None => Err(DeserializeError::MissingField),
29 }
30 }
31}
32
33pub trait ToNbtTag: Sized {
34 fn to_nbt_tag(self) -> crate::owned::NbtTag;
35 fn to_optional_nbt_tag(self) -> Option<crate::owned::NbtTag> {
36 Some(self.to_nbt_tag())
37 }
38}
39
40impl<K: Display + FromStr + Eq + Hash, V: FromNbtTag> Deserialize for HashMap<K, V> {
41 fn from_compound(compound: crate::borrow::NbtCompound) -> Result<Self, DeserializeError> {
42 let mut hashmap = HashMap::new();
43
44 for (k, v) in compound.iter() {
45 let k_str = k.to_str();
46 let k_parsed = k_str
47 .parse()
48 .map_err(|_| DeserializeError::MismatchedFieldType("key".to_owned()))?;
49
50 let v_parsed = V::from_nbt_tag(v).ok_or_else(|| {
51 DeserializeError::MismatchedFieldType(format!("value for key {k_str}"))
52 })?;
53
54 hashmap.insert(k_parsed, v_parsed);
55 }
56
57 Ok(hashmap)
58 }
59}
60impl<K: Display + FromStr + Eq + Hash, V: ToNbtTag> Serialize for HashMap<K, V> {
61 fn to_compound(self) -> crate::owned::NbtCompound {
62 let mut compound = crate::owned::NbtCompound::new();
63
64 for (k, v) in self {
65 compound.insert(k.to_string(), v.to_nbt_tag());
66 }
67
68 compound
69 }
70}
71
72impl Deserialize for crate::owned::NbtCompound {
73 fn from_compound(compound: crate::borrow::NbtCompound) -> Result<Self, DeserializeError> {
74 Ok(compound.to_owned())
75 }
76}
77impl Serialize for crate::owned::NbtCompound {
78 fn to_compound(self) -> crate::owned::NbtCompound {
79 self
80 }
81}
82
83impl<T: Deserialize> FromNbtTag for T {
84 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
85 tag.compound().and_then(|c| Self::from_compound(c).ok())
86 }
87}
88
89impl<T: Serialize> ToNbtTag for T {
90 fn to_nbt_tag(self) -> crate::owned::NbtTag {
91 crate::owned::NbtTag::Compound(self.to_compound())
92 }
93}
94
95impl FromNbtTag for crate::owned::NbtTag {
96 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
97 Some(tag.to_owned())
98 }
99}
100impl ToNbtTag for crate::owned::NbtTag {
101 fn to_nbt_tag(self) -> crate::owned::NbtTag {
102 self
103 }
104}
105
106impl FromNbtTag for i8 {
108 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
109 tag.byte()
110 }
111}
112impl ToNbtTag for i8 {
113 fn to_nbt_tag(self) -> crate::owned::NbtTag {
114 crate::owned::NbtTag::Byte(self)
115 }
116}
117
118impl FromNbtTag for i16 {
119 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
120 tag.short()
121 }
122}
123impl ToNbtTag for i16 {
124 fn to_nbt_tag(self) -> crate::owned::NbtTag {
125 crate::owned::NbtTag::Short(self)
126 }
127}
128
129impl FromNbtTag for i32 {
130 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
131 tag.int()
132 }
133}
134impl ToNbtTag for i32 {
135 fn to_nbt_tag(self) -> crate::owned::NbtTag {
136 crate::owned::NbtTag::Int(self)
137 }
138}
139
140impl FromNbtTag for i64 {
141 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
142 tag.long()
143 }
144}
145impl ToNbtTag for i64 {
146 fn to_nbt_tag(self) -> crate::owned::NbtTag {
147 crate::owned::NbtTag::Long(self)
148 }
149}
150
151impl FromNbtTag for f32 {
152 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
153 tag.float()
154 }
155}
156impl ToNbtTag for f32 {
157 fn to_nbt_tag(self) -> crate::owned::NbtTag {
158 crate::owned::NbtTag::Float(self)
159 }
160}
161
162impl FromNbtTag for f64 {
163 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
164 tag.double()
165 }
166}
167impl ToNbtTag for f64 {
168 fn to_nbt_tag(self) -> crate::owned::NbtTag {
169 crate::owned::NbtTag::Double(self)
170 }
171}
172
173impl FromNbtTag for String {
174 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
175 tag.string().map(|s| s.to_string())
176 }
177}
178impl ToNbtTag for String {
179 fn to_nbt_tag(self) -> crate::owned::NbtTag {
180 crate::owned::NbtTag::String(self.into())
181 }
182}
183
184impl ToNbtTag for &str {
185 fn to_nbt_tag(self) -> crate::owned::NbtTag {
186 crate::owned::NbtTag::String(self.into())
187 }
188}
189
190impl FromNbtTag for u8 {
192 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
193 tag.byte().map(|b| b as u8)
194 }
195}
196impl ToNbtTag for u8 {
197 fn to_nbt_tag(self) -> crate::owned::NbtTag {
198 crate::owned::NbtTag::Byte(self as i8)
199 }
200}
201
202impl FromNbtTag for u16 {
203 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
204 tag.short().map(|s| s as u16)
205 }
206}
207impl ToNbtTag for u16 {
208 fn to_nbt_tag(self) -> crate::owned::NbtTag {
209 crate::owned::NbtTag::Short(self as i16)
210 }
211}
212
213impl FromNbtTag for u32 {
214 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
215 tag.int().map(|i| i as u32)
216 }
217}
218impl ToNbtTag for u32 {
219 fn to_nbt_tag(self) -> crate::owned::NbtTag {
220 crate::owned::NbtTag::Int(self as i32)
221 }
222}
223
224impl FromNbtTag for u64 {
225 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
226 tag.long().map(|l| l as u64)
227 }
228}
229impl ToNbtTag for u64 {
230 fn to_nbt_tag(self) -> crate::owned::NbtTag {
231 crate::owned::NbtTag::Long(self as i64)
232 }
233}
234
235impl FromNbtTag for Vec<String> {
237 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
238 tag.list().and_then(|l| {
239 l.strings()
240 .map(|s| s.iter().map(|s| s.to_string()).collect())
241 })
242 }
243}
244impl ToNbtTag for Vec<String> {
245 fn to_nbt_tag(self) -> crate::owned::NbtTag {
246 crate::owned::NbtTag::List(crate::owned::NbtList::String(
247 self.into_iter().map(|s| s.into()).collect(),
248 ))
249 }
250}
251
252impl<T: FromNbtTag> FromNbtTag for Option<T> {
254 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
255 Some(T::from_nbt_tag(tag))
256 }
257 fn from_optional_nbt_tag(
258 tag: Option<crate::borrow::NbtTag>,
259 ) -> Result<Option<Self>, DeserializeError> {
260 match tag {
261 Some(tag) => Ok(Some(T::from_nbt_tag(tag))),
262 None => Ok(Some(None)),
263 }
264 }
265}
266impl<T: ToNbtTag> ToNbtTag for Option<T> {
267 fn to_nbt_tag(self) -> crate::owned::NbtTag {
268 panic!("Called to_nbt_tag on Option<T>. Use to_optional_nbt_tag instead.")
269 }
270 fn to_optional_nbt_tag(self) -> Option<crate::owned::NbtTag> {
271 self.map(|t| t.to_nbt_tag())
272 }
273}
274
275impl<T: Deserialize> FromNbtTag for Vec<Option<T>> {
276 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
278 let list = tag.list()?;
279 let list = list.compounds()?;
280 let mut vec = Vec::with_capacity(list.approx_len() as usize);
281 for tag in list {
282 if tag.is_empty() {
283 vec.push(None);
284 } else {
285 vec.push(Some(T::from_compound(tag).ok()?));
286 }
287 }
288
289 Some(vec)
290 }
291}
292impl<T: Serialize> ToNbtTag for Vec<Option<T>> {
293 fn to_nbt_tag(self) -> crate::owned::NbtTag {
294 crate::owned::NbtTag::List(crate::owned::NbtList::Compound(
295 self.into_iter()
296 .map(|t| match t {
297 Some(t) => t.to_compound(),
298 None => crate::owned::NbtCompound::new(),
299 })
300 .collect(),
301 ))
302 }
303}
304
305impl<T: Deserialize> FromNbtTag for Vec<T> {
306 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
307 let list = tag.list()?;
308 let list = list.compounds()?;
309 let mut vec = Vec::with_capacity(list.approx_len() as usize);
310 for tag in list {
311 vec.push(T::from_compound(tag).ok()?);
312 }
313
314 Some(vec)
315 }
316}
317impl<T: Serialize> ToNbtTag for Vec<T> {
318 fn to_nbt_tag(self) -> crate::owned::NbtTag {
319 crate::owned::NbtTag::List(crate::owned::NbtList::Compound(
320 self.into_iter().map(|t| t.to_compound()).collect(),
321 ))
322 }
323}
324
325impl FromNbtTag for bool {
326 fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
327 tag.byte().map(|b| b != 0)
328 }
329}
330impl ToNbtTag for bool {
331 fn to_nbt_tag(self) -> crate::owned::NbtTag {
332 crate::owned::NbtTag::Byte(if self { 1 } else { 0 })
333 }
334}
335
336impl ToNbtTag for crate::owned::NbtList {
337 fn to_nbt_tag(self) -> crate::owned::NbtTag {
338 crate::owned::NbtTag::List(self)
339 }
340}