simdnbt/
traits.rs

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
106// standard nbt types
107impl 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
190// unsigned integers
191impl 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
235// lists
236impl 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
252// slightly less standard types
253impl<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    /// A list of compounds where `None` is an empty compound
277    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}