blocky_nbt/
lib.rs

1#[macro_use]
2extern crate lazy_static;
3
4mod decoder;
5mod encoder;
6#[macro_use]
7mod tag;
8
9pub use tag::*;
10
11use std::str;
12use std::ops;
13
14#[derive(Debug, PartialEq, Clone)]
15pub struct Nbt {
16    pub name: String,
17    pub tag: Tag,
18}
19
20impl Nbt {
21    pub fn new(name: String, tag: Tag) -> Self {
22        Self { name, tag }
23    }
24
25    pub fn get<I: Index>(&self, index: I) -> Option<&Tag> {
26        self.tag.get(index)
27    }
28
29    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Tag> {
30        self.tag.get_mut(index)
31    }
32
33    pub fn insert<I: Index>(&mut self, index: I, value: Tag) {
34        self.tag.insert(index, value);
35    }
36}
37
38impl<I: Index> ops::Index<I> for Tag {
39    type Output = Self;
40
41    fn index(&self, index: I) -> &Self::Output {
42        match self.get(index) {
43            Some(tag) => tag,
44            None => &Tag::End,
45        }
46    }
47}
48
49impl<I: Index> ops::IndexMut<I> for Tag {
50    fn index_mut(&mut self, index: I) -> &mut Self::Output {
51        index.index_or_insert(self)
52    }
53}
54
55impl ops::Index<&str> for Nbt {
56    type Output = Tag;
57
58    fn index<'a>(&self, index: &str) -> &Self::Output {
59        &self.tag[index]
60    }
61}
62
63impl ops::IndexMut<&str> for Nbt {
64    fn index_mut(&mut self, index: &str) -> &mut Self::Output {
65        &mut self.tag[index]
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::{Kind, Nbt, Tag, tag};
72    use std::io::Cursor;
73
74    fn nbt(data: &[u8]) -> Nbt {
75        let data = data.to_vec();
76        let mut data = Cursor::new(data);
77
78        // decode nbt from data
79        let nbt = Nbt::decode(&mut data);
80
81        assert!(nbt.is_ok(), "failed to decode nbt");
82
83        // unwrap nbt data
84        let nbt = nbt.unwrap();
85
86        assert!(match nbt.tag.kind() {
87            Kind::Compound => true,
88            _ => false,
89        }, "nbt does not match expected type");
90
91        nbt
92    }
93
94    #[test]
95    fn uncompressed() {
96        nbt(include_bytes!("../examples/uncompressed.nbt"));
97    }
98
99    #[test]
100    fn compressed() {
101        nbt(include_bytes!("../examples/compressed.nbt"));
102    }
103
104    #[cfg(feature = "preserve-order")]
105    #[test]
106    fn insertion_order() {
107        let bytes = include_bytes!("../examples/uncompressed.nbt");
108        let nbt = nbt(bytes);
109        let mut new_bytes = vec![];
110
111        assert!(nbt.encode(&mut new_bytes, false).is_ok(), "failed to encode");
112        assert!(bytes.len() == new_bytes.len(), "size doesn't match");
113        assert!({
114            let len = bytes.len();
115            let mut matches = true;
116
117            for i in 0..len {
118                if bytes[i] != new_bytes[i] {
119                    matches = false;
120                    break;
121                }
122            }
123
124            matches
125        }, "data doesn't match")
126    }
127
128    #[test]
129    fn string() {
130        let nbt: Tag = String::from("\"\"\\'this is a test!").into();
131        assert_eq!(format!("{}", nbt), "'\"\"\\\\\\'this is a test!'");
132    }
133
134    #[test]
135    fn assignment() {
136        let mut nbt = nbt(include_bytes!("../examples/uncompressed.nbt"));
137        nbt["testing"] = tag!("[B;8b,2b]");
138
139        assert_eq!(nbt["testing"], tag!("[B;8b,2b]"));
140    }
141
142    #[test]
143    fn display() {
144        let byte_array = tag!("[B;1B,2B,6b,10b]").to_string();
145        let list = tag!("[5l,10L,20l]").to_string();
146        let compound = tag!("{name:'Jaden'}").to_string();
147
148        assert_eq!(byte_array, "[B;1b,2b,6b,10b]");
149        assert_eq!(list, "[5L,10L,20L]");
150        assert_eq!(compound, "{name:\"Jaden\"}");
151    }
152
153    #[test]
154    fn verify_value() {
155        let nbt = nbt(include_bytes!("../examples/uncompressed.nbt"));
156        let seed: i64 = (&nbt["Data"]["RandomSeed"]).into();
157        let version_name: String = (&nbt["Data"]["Version"]["Name"]).into();
158
159        assert_eq!(seed, 4443890602994873962);
160        assert_eq!(version_name, "1.14.1 Pre-Release 2");
161    }
162}