1use linked_hash_map::LinkedHashMap;
53use std::fmt::{Debug, Display, Formatter};
54use std::{
55 convert::{TryFrom, TryInto},
56 fmt,
57};
58
59pub mod decode;
60pub mod encode;
61
62#[derive(Debug, Clone)]
64pub enum Tag {
65 Byte(i8),
66 Short(i16),
67 Int(i32),
68 Long(i64),
69 Float(f32),
70 Double(f64),
71 ByteArray(Vec<i8>),
72 String(String),
73 List(Vec<Tag>),
74 Compound(CompoundTag),
75 IntArray(Vec<i32>),
76 LongArray(Vec<i64>),
77}
78
79impl Tag {
80 fn type_id(&self) -> u8 {
81 match self {
82 Tag::Byte(_) => 1,
83 Tag::Short(_) => 2,
84 Tag::Int(_) => 3,
85 Tag::Long(_) => 4,
86 Tag::Float(_) => 5,
87 Tag::Double(_) => 6,
88 Tag::ByteArray(_) => 7,
89 Tag::String(_) => 8,
90 Tag::List(_) => 9,
91 Tag::Compound(_) => 10,
92 Tag::IntArray(_) => 11,
93 Tag::LongArray(_) => 12,
94 }
95 }
96
97 fn type_name(&self) -> &'static str {
98 match self {
99 Tag::Byte(_) => "TAG_Byte",
100 Tag::Short(_) => "TAG_Short",
101 Tag::Int(_) => "TAG_Int",
102 Tag::Long(_) => "TAG_Long",
103 Tag::Float(_) => "TAG_Float",
104 Tag::Double(_) => "TAG_Double",
105 Tag::ByteArray(_) => "TAG_Byte_Array",
106 Tag::String(_) => "TAG_String",
107 Tag::List(_) => "TAG_List",
108 Tag::Compound(_) => "TAG_Compound",
109 Tag::IntArray(_) => "TAG_Int_Array",
110 Tag::LongArray(_) => "TAG_Long_Array",
111 }
112 }
113}
114
115macro_rules! impl_from_for_copy {
116 ($type: ty, $tag: ident) => {
117 impl From<$type> for Tag {
118 fn from(data: $type) -> Self {
119 Tag::$tag(data)
120 }
121 }
122
123 impl<'a> TryFrom<&'a Tag> for $type {
124 type Error = &'a Tag;
128
129 fn try_from(tag: &'a Tag) -> Result<Self, Self::Error> {
130 match tag {
131 Tag::$tag(value) => Ok(*value),
132 actual_tag => Err(actual_tag),
133 }
134 }
135 }
136
137 impl<'a> TryFrom<&'a mut Tag> for &'a mut $type {
138 type Error = &'a Tag;
139
140 fn try_from(tag: &'a mut Tag) -> Result<&mut$type, Self::Error> {
141 match tag {
142 Tag::$tag(value) => Ok(value),
143 actual_tag => Err(actual_tag),
144 }
145 }
146 }
147 };
148}
149
150macro_rules! impl_from_for_ref {
151 ($type: ty, $tag: ident) => {
152 impl From<$type> for Tag {
153 fn from(data: $type) -> Self {
154 Tag::$tag(data)
155 }
156 }
157
158 impl<'a> TryFrom<&'a Tag> for &'a $type {
159 type Error = &'a Tag;
160
161 fn try_from(tag: &'a Tag) -> Result<&$type, Self::Error> {
162 match tag {
163 Tag::$tag(value) => Ok(value),
164 actual_tag => Err(actual_tag),
165 }
166 }
167 }
168
169 impl<'a> TryFrom<&'a mut Tag> for &'a mut $type {
170 type Error = &'a Tag;
171
172 fn try_from(tag: &'a mut Tag) -> Result<&mut$type, Self::Error> {
173 match tag {
174 Tag::$tag(value) => Ok(value),
175 actual_tag => Err(actual_tag),
176 }
177 }
178 }
179 };
180}
181
182impl_from_for_copy!(i8, Byte);
183impl_from_for_copy!(i16, Short);
184impl_from_for_copy!(i32, Int);
185impl_from_for_copy!(i64, Long);
186impl_from_for_copy!(f32, Float);
187impl_from_for_copy!(f64, Double);
188impl_from_for_ref!(Vec<i8>, ByteArray);
189impl_from_for_ref!(String, String);
190impl_from_for_ref!(Vec<Tag>, List);
191impl_from_for_ref!(CompoundTag, Compound);
192impl_from_for_ref!(Vec<i32>, IntArray);
193impl_from_for_ref!(Vec<i64>, LongArray);
194
195#[derive(Clone)]
196pub struct CompoundTag {
197 pub name: Option<String>,
198 tags: LinkedHashMap<String, Tag>,
199}
200
201#[derive(Debug)]
203pub enum CompoundTagError<'a> {
204 TagNotFound {
206 name: &'a str,
208 },
209 TagWrongType {
211 name: &'a str,
213 actual_tag: &'a Tag,
215 },
216}
217
218impl<'a> std::error::Error for CompoundTagError<'a> {
219 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
220 None
221 }
222}
223
224impl<'a> Display for CompoundTagError<'a> {
225 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
226 match self {
227 CompoundTagError::TagNotFound { name } => write!(f, "Tag {} not found", name),
228 CompoundTagError::TagWrongType { name, actual_tag } => {
229 write!(f, "Tag {} has type {}", name, actual_tag.type_name())
230 }
231 }
232 }
233}
234
235macro_rules! define_primitive_type (
236 ($type: ident, $tag: ident, $getter_name: ident, $setter_name: ident) => (
237 pub fn $setter_name(&mut self, name: impl ToString, value: $type) {
238 self.tags.insert(name.to_string(), Tag::$tag(value));
239 }
240
241 pub fn $getter_name<'a>(&'a self, name: &'a str) -> Result<$type, CompoundTagError<'a>> {
242 match self.tags.get(name) {
243 Some(tag) => match tag {
244 Tag::$tag(value) => Ok(*value),
245 actual_tag => Err(CompoundTagError::TagWrongType { name, actual_tag }),
246 },
247 None => Err(CompoundTagError::TagNotFound { name }),
248 }
249 }
250 );
251);
252
253macro_rules! define_array_type (
254 ($type: ident, $tag: ident, $getter_name: ident, $setter_name: ident) => (
255 pub fn $setter_name(&mut self, name: impl ToString, value: Vec<$type>) {
256 self.tags.insert(name.to_string(), Tag::$tag(value));
257 }
258
259 pub fn $getter_name<'a>(&'a self, name: &'a str) -> Result<&Vec<$type>, CompoundTagError<'a>> {
260 match self.tags.get(name) {
261 Some(tag) => match tag {
262 Tag::$tag(value) => Ok(value),
263 actual_tag => Err(CompoundTagError::TagWrongType { name, actual_tag }),
264 },
265 None => Err(CompoundTagError::TagNotFound { name }),
266 }
267 }
268 );
269);
270
271macro_rules! define_list_type (
272 ($type: ident, $tag: ident, $getter_name: ident, $setter_name: ident) => (
273 pub fn $setter_name(&mut self, name: impl ToString, vec: impl IntoIterator<Item=$type>) {
274 let mut tags = Vec::new();
275
276 for value in vec {
277 tags.push(Tag::$tag(value));
278 }
279
280 self.tags.insert(name.to_string(), Tag::List(tags));
281 }
282
283 pub fn $getter_name<'a>(&'a self, name: &'a str) -> Result<Vec<$type>, CompoundTagError<'a>> {
284 let tags = self.get_vec(name)?;
285 let mut vec = Vec::new();
286
287 for tag in tags {
288 match tag {
289 Tag::$tag(value) => vec.push(*value),
290 actual_tag => return Err(CompoundTagError::TagWrongType { name, actual_tag }),
291 }
292 }
293
294 Ok(vec)
295 }
296 );
297);
298
299impl CompoundTag {
300 pub fn new() -> Self {
301 CompoundTag {
302 name: None,
303 tags: LinkedHashMap::new(),
304 }
305 }
306
307 pub fn named(name: impl ToString) -> Self {
308 CompoundTag {
309 name: Some(name.to_string()),
310 tags: LinkedHashMap::new(),
311 }
312 }
313
314 pub fn is_empty(&self) -> bool {
315 self.tags.is_empty()
316 }
317
318 pub fn contains_key(&self, name: &str) -> bool {
319 self.tags.contains_key(name)
320 }
321
322 pub fn insert(&mut self, name: impl ToString, tag: impl Into<Tag>) {
323 self.tags.insert(name.to_string(), tag.into());
324 }
325
326 pub fn get<'a, 'b: 'a, T: TryFrom<&'a Tag>>(&'a self, name: &'b str) -> Result<T, CompoundTagError> {
327 match self.tags.get(name) {
328 Some(tag) => match tag.try_into() {
329 Ok(value) => Ok(value),
330 Err(..) => Err(CompoundTagError::TagWrongType {
331 name,
332 actual_tag: tag,
333 }),
334 },
335 None => Err(CompoundTagError::TagNotFound { name }),
336 }
337 }
338
339 pub fn get_mut<'a, 'b, T>(&'a mut self, name: &'b str) -> Result<T, CompoundTagError>
340 where
341 'b: 'a,
342 T: TryFrom<&'a mut Tag, Error = &'a Tag>,
343 {
344 match self.tags.get_mut(name) {
345 Some(tag) => match tag.try_into() {
346 Ok(value) => Ok(value),
347 Err(actual_tag) => Err(CompoundTagError::TagWrongType { name, actual_tag }),
348 },
349 None => Err(CompoundTagError::TagNotFound { name }),
350 }
351 }
352
353 define_primitive_type!(i8, Byte, get_i8, insert_i8);
354 define_primitive_type!(i16, Short, get_i16, insert_i16);
355 define_primitive_type!(i32, Int, get_i32, insert_i32);
356 define_primitive_type!(i64, Long, get_i64, insert_i64);
357 define_primitive_type!(f32, Float, get_f32, insert_f32);
358 define_primitive_type!(f64, Double, get_f64, insert_f64);
359 define_array_type!(i8, ByteArray, get_i8_vec, insert_i8_vec);
360 define_array_type!(i32, IntArray, get_i32_vec, insert_i32_vec);
361 define_array_type!(i64, LongArray, get_i64_vec, insert_i64_vec);
362 define_list_type!(i16, Short, get_i16_vec, insert_i16_vec);
363 define_list_type!(f32, Float, get_f32_vec, insert_f32_vec);
364 define_list_type!(f64, Double, get_f64_vec, insert_f64_vec);
365
366 pub fn insert_bool(&mut self, name: &str, value: bool) {
367 if value {
368 self.insert_i8(name, 1);
369 } else {
370 self.insert_i8(name, 0);
371 }
372 }
373
374 pub fn get_bool<'a>(&'a self, name: &'a str) -> Result<bool, CompoundTagError<'a>> {
375 Ok(self.get_i8(name)? == 1)
376 }
377
378 pub fn insert_str(&mut self, name: impl ToString, value: impl ToString) {
379 self.tags
380 .insert(name.to_string(), Tag::String(value.to_string()));
381 }
382
383 pub fn get_str<'a>(&'a self, name: &'a str) -> Result<&str, CompoundTagError<'a>> {
384 match self.tags.get(name) {
385 Some(tag) => match tag {
386 Tag::String(value) => Ok(value),
387 actual_tag => Err(CompoundTagError::TagWrongType { name, actual_tag }),
388 },
389 None => Err(CompoundTagError::TagNotFound { name }),
390 }
391 }
392
393 pub fn insert_compound_tag(&mut self, name: impl ToString, value: CompoundTag) {
394 self.tags.insert(name.to_string(), Tag::Compound(value));
395 }
396
397 pub fn get_compound_tag<'a>(
398 &'a self,
399 name: &'a str,
400 ) -> Result<&CompoundTag, CompoundTagError<'a>> {
401 match self.tags.get(name) {
402 Some(tag) => match tag {
403 Tag::Compound(value) => Ok(value),
404 actual_tag => Err(CompoundTagError::TagWrongType { name, actual_tag }),
405 },
406 None => Err(CompoundTagError::TagNotFound { name }),
407 }
408 }
409
410 fn get_vec<'a>(&'a self, name: &'a str) -> Result<&Vec<Tag>, CompoundTagError<'a>> {
411 match self.tags.get(name) {
412 Some(tag) => match tag {
413 Tag::List(value) => Ok(value),
414 actual_tag => Err(CompoundTagError::TagWrongType { name, actual_tag }),
415 },
416 None => Err(CompoundTagError::TagNotFound { name }),
417 }
418 }
419
420 pub fn insert_str_vec(
421 &mut self,
422 name: impl ToString,
423 vec: impl IntoIterator<Item = impl ToString>,
424 ) {
425 let mut tags = Vec::new();
426
427 for value in vec {
428 tags.push(Tag::String(value.to_string()));
429 }
430
431 self.tags.insert(name.to_string(), Tag::List(tags));
432 }
433
434 pub fn get_str_vec<'a>(&'a self, name: &'a str) -> Result<Vec<&str>, CompoundTagError<'a>> {
435 let tags = self.get_vec(name)?;
436 let mut vec = Vec::new();
437
438 for tag in tags {
439 match tag {
440 Tag::String(value) => vec.push(value.as_str()),
441 actual_tag => return Err(CompoundTagError::TagWrongType { name, actual_tag }),
442 }
443 }
444
445 Ok(vec)
446 }
447
448 pub fn insert_compound_tag_vec(
449 &mut self,
450 name: impl ToString,
451 vec: impl IntoIterator<Item = CompoundTag>,
452 ) {
453 let mut tags = Vec::new();
454
455 for value in vec {
456 tags.push(Tag::Compound(value));
457 }
458
459 self.tags.insert(name.to_string(), Tag::List(tags));
460 }
461
462 pub fn get_compound_tag_vec<'a>(
463 &'a self,
464 name: &'a str,
465 ) -> Result<Vec<&CompoundTag>, CompoundTagError<'a>> {
466 let tags = self.get_vec(name)?;
467 let mut vec = Vec::new();
468
469 for tag in tags {
470 match tag {
471 Tag::Compound(value) => vec.push(value),
472 actual_tag => return Err(CompoundTagError::TagWrongType { name, actual_tag }),
473 }
474 }
475
476 Ok(vec)
477 }
478
479 pub fn iter(&self) -> impl DoubleEndedIterator<Item = (&String, &Tag)> {
480 self.tags.iter()
481 }
482
483 pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = (&String, &mut Tag)> {
484 self.tags.iter_mut()
485 }
486}
487
488pub struct IntoIter(linked_hash_map::IntoIter<String, Tag>);
489
490impl Iterator for IntoIter {
491 type Item = (String, Tag);
492
493 fn next(&mut self) -> Option<Self::Item> {
494 self.0.next()
495 }
496}
497
498impl DoubleEndedIterator for IntoIter {
499 fn next_back(&mut self) -> Option<Self::Item> {
500 self.0.next_back()
501 }
502}
503
504impl IntoIterator for CompoundTag {
505 type Item = (String, Tag);
506 type IntoIter = IntoIter;
507
508 fn into_iter(self) -> Self::IntoIter {
509 IntoIter(self.tags.into_iter())
510 }
511}
512
513impl std::iter::FromIterator<(String, Tag)> for CompoundTag {
514 fn from_iter<T: IntoIterator<Item = (String, Tag)>>(iter: T) -> Self {
515 CompoundTag {
516 name: None,
517 tags: iter.into_iter().collect(),
518 }
519 }
520}
521
522impl<'a> std::iter::FromIterator<(&'a str, Tag)> for CompoundTag {
523 fn from_iter<T: IntoIterator<Item = (&'a str, Tag)>>(iter: T) -> Self {
524 CompoundTag {
525 name: None,
526 tags: iter
527 .into_iter()
528 .map(|(name, tag)| (name.into(), tag))
529 .collect(),
530 }
531 }
532}
533
534impl Debug for CompoundTag {
535 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
536 let name_ref = self.name.as_ref().map(|x| &**x);
537 fmt_tag(f, name_ref, &Tag::Compound(self.clone()), 0)
538 }
539}
540
541fn fmt_tag(
542 f: &mut Formatter,
543 name: Option<&str>,
544 tag: &Tag,
545 indent: usize,
546) -> Result<(), fmt::Error> {
547 fmt_indent(f, indent)?;
548
549 let type_name = tag.type_name();
550
551 match tag {
552 Tag::Byte(value) => fmt_simple_tag(f, type_name, name, value)?,
553 Tag::Short(value) => fmt_simple_tag(f, type_name, name, value)?,
554 Tag::Int(value) => fmt_simple_tag(f, type_name, name, value)?,
555 Tag::Long(value) => fmt_simple_tag(f, type_name, name, value)?,
556 Tag::Float(value) => fmt_simple_tag(f, type_name, name, value)?,
557 Tag::Double(value) => fmt_simple_tag(f, type_name, name, value)?,
558 Tag::ByteArray(value) => fmt_array_tag(f, type_name, name, value)?,
559 Tag::String(value) => fmt_simple_tag(f, type_name, name, value)?,
560 Tag::List(value) => {
561 let length = value.len();
562
563 fmt_list_start(f, type_name, name, length)?;
564
565 for tag in value {
566 fmt_tag(f, None, tag, indent + 2)?;
567 }
568
569 if length > 0 {
570 fmt_list_end(f, indent)?;
571 }
572 }
573 Tag::Compound(value) => {
574 let name_ref = name.as_ref().map(|x| &**x);
575 let length = value.tags.len();
576
577 fmt_list_start(f, type_name, name_ref, length)?;
578
579 for (name, tag) in &value.tags {
580 fmt_tag(f, Some(name.as_str()), tag, indent + 2)?;
581 }
582
583 if length > 0 {
584 fmt_list_end(f, indent)?;
585 }
586 }
587 Tag::IntArray(value) => fmt_array_tag(f, type_name, name, value)?,
588 Tag::LongArray(value) => fmt_array_tag(f, type_name, name, value)?,
589 };
590
591 Ok(())
592}
593
594fn fmt_simple_tag<V: Display>(
595 f: &mut Formatter,
596 type_name: &str,
597 name: Option<&str>,
598 value: V,
599) -> Result<(), fmt::Error> {
600 writeln!(f, "{}('{}'): '{}'", type_name, fmt_str_opt(name), value)
601}
602
603fn fmt_array_tag<V: Debug>(
604 f: &mut Formatter,
605 type_name: &str,
606 name: Option<&str>,
607 value: V,
608) -> Result<(), fmt::Error> {
609 writeln!(f, "{}('{}'): '{:?}'", type_name, fmt_str_opt(name), value)
610}
611
612fn fmt_list_start(
613 f: &mut Formatter,
614 type_name: &str,
615 name: Option<&str>,
616 length: usize,
617) -> Result<(), fmt::Error> {
618 let fmt_name = fmt_str_opt(name);
619
620 match length {
621 0 => writeln!(f, "{}('{}'): 0 entries", type_name, fmt_name),
622 1 => writeln!(f, "{}('{}'): 1 entry {{", type_name, fmt_name),
623 _ => writeln!(f, "{}('{}'): {} entries {{", type_name, fmt_name, length),
624 }
625}
626
627fn fmt_list_end(f: &mut Formatter, indent: usize) -> Result<(), fmt::Error> {
628 fmt_indent(f, indent)?;
629 writeln!(f, "}}")
630}
631
632fn fmt_indent(f: &mut Formatter, indent: usize) -> Result<(), fmt::Error> {
633 write!(f, "{:indent$}", "", indent = indent)
634}
635
636fn fmt_str_opt(name: Option<&str>) -> &str {
637 match name {
638 Some(value) => value,
639 None => "",
640 }
641}
642
643impl Display for CompoundTag {
644 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
645 write!(f, "{{")?;
648 let mut first = true;
649 for (name, value) in &self.tags {
650 write!(f, "{}{:?}:{}", if first { "" } else { "," }, name, value)?;
651 first = false;
652 }
653 write!(f, "}}")
654 }
655}
656
657impl Display for Tag {
659 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
660 fn format_list<T: Display>(
661 f: &mut Formatter<'_>,
662 type_header: &'static str,
663 list: &Vec<T>,
664 ) -> Result<(), fmt::Error> {
665 write!(f, "[{}", type_header)?;
666 let mut first = true;
667 for elem in list {
668 write!(f, "{}{}", if first { "" } else { "," }, elem)?;
669 first = false;
670 }
671 write!(f, "]")
672 }
673 match self {
674 Tag::Byte(data) => write!(f, "{}b", data),
675 Tag::Short(data) => write!(f, "{}s", data),
676 Tag::Int(data) => write!(f, "{}", data),
677 Tag::Long(data) => write!(f, "{}l", data),
678 Tag::Float(data) => write!(f, "{}f", data),
679 Tag::Double(data) => write!(f, "{}d", data),
680 Tag::ByteArray(data) => format_list(f, "B;", data),
681 Tag::String(data) => write!(f, "{:?}", data),
682 Tag::List(data) => format_list(f, "", data),
683 Tag::Compound(data) => write!(f, "{}", data),
684 Tag::IntArray(data) => format_list(f, "I;", data),
685 Tag::LongArray(data) => format_list(f, "L;", data),
686 }
687 }
688}
689
690#[test]
691fn test_compound_tag_i8() {
692 let mut compound_tag = CompoundTag::new();
693 compound_tag.insert_i8("i8", 1);
694
695 assert_eq!(compound_tag.get_i8("i8").unwrap(), 1i8);
696}
697
698#[test]
699fn test_compound_tag_bool() {
700 let mut compound_tag = CompoundTag::new();
701 compound_tag.insert_bool("bool", true);
702
703 assert!(compound_tag.get_bool("bool").unwrap());
704}
705
706#[test]
707fn test_compound_tag_i16() {
708 let mut compound_tag = CompoundTag::new();
709 compound_tag.insert_i16("i16", 2);
710
711 assert_eq!(compound_tag.get_i16("i16").unwrap(), 2i16);
712}
713
714#[test]
715fn test_compound_tag_i32() {
716 let mut compound_tag = CompoundTag::new();
717 compound_tag.insert_i32("i32", 3);
718
719 assert_eq!(compound_tag.get_i32("i32").unwrap(), 3i32);
720}
721
722#[test]
723fn test_compound_tag_i64() {
724 let mut compound_tag = CompoundTag::new();
725 compound_tag.insert_i64("i64", 4);
726
727 assert_eq!(compound_tag.get_i64("i64").unwrap(), 4i64);
728}
729
730#[test]
731fn test_compound_tag_f32() {
732 let mut compound_tag = CompoundTag::new();
733 compound_tag.insert_f32("f32", 5.1);
734
735 assert_eq!(compound_tag.get_f32("f32").unwrap(), 5.1f32);
736}
737
738#[test]
739fn test_compound_tag_f64() {
740 let mut compound_tag = CompoundTag::new();
741 compound_tag.insert_f64("f64", 6.3322);
742
743 assert_eq!(compound_tag.get_f64("f64").unwrap(), 6.3322f64);
744}
745
746#[test]
747fn test_compound_tag_str() {
748 let mut compound_tag = CompoundTag::new();
749 compound_tag.insert_str("str", "hello world");
750
751 assert_eq!(compound_tag.get_str("str").unwrap(), "hello world");
752}
753
754#[test]
755fn test_compound_tag_nested_compound_tag() {
756 let mut compound_tag = CompoundTag::new();
757 let mut insert_nested_compound_tag = CompoundTag::named("nested");
758 insert_nested_compound_tag.insert_i8("i8", 1);
759 insert_nested_compound_tag.insert_str("str", "hello world");
760
761 compound_tag.insert_compound_tag("nested_compound_tag", insert_nested_compound_tag);
762
763 let get_nested_compound_tag = compound_tag
764 .get_compound_tag("nested_compound_tag")
765 .unwrap();
766
767 assert_eq!(get_nested_compound_tag.get_i8("i8").unwrap(), 1i8);
768 assert_eq!(
769 get_nested_compound_tag.get_str("str").unwrap(),
770 "hello world"
771 );
772}
773
774#[test]
775fn test_compound_tag_i8_vec() {
776 let mut compound_tag = CompoundTag::new();
777 compound_tag.insert_i8_vec("i8_vec", vec![0, 1]);
778
779 let i8_vec = compound_tag.get_i8_vec("i8_vec").unwrap();
780 assert_eq!(i8_vec[0], 0);
781 assert_eq!(i8_vec[1], 1);
782}
783
784#[test]
785fn test_compound_tag_i32_vec() {
786 let mut compound_tag = CompoundTag::new();
787 compound_tag.insert_i32_vec("i32_vec", vec![7, 8, 9]);
788
789 let i32_vec = compound_tag.get_i32_vec("i32_vec").unwrap();
790
791 assert_eq!(i32_vec[0], 7i32);
792 assert_eq!(i32_vec[1], 8i32);
793 assert_eq!(i32_vec[2], 9i32);
794}
795
796#[test]
797fn test_compound_tag_i64_vec() {
798 let mut compound_tag = CompoundTag::new();
799 compound_tag.insert_i64_vec("i64_vec", vec![10, 11, 12]);
800 let i64_vec = compound_tag.get_i64_vec("i64_vec").unwrap();
801
802 assert_eq!(i64_vec[0], 10i64);
803 assert_eq!(i64_vec[1], 11i64);
804 assert_eq!(i64_vec[2], 12i64);
805}
806
807#[test]
808fn test_compound_tag_str_vec() {
809 let mut compound_tag = CompoundTag::new();
810 let insert_str_vec = vec!["a", "b", "c"];
811
812 compound_tag.insert_str_vec("str_vec", insert_str_vec);
813
814 let get_str_vec = compound_tag.get_str_vec("str_vec").unwrap();
815 assert_eq!(get_str_vec[0], "a");
816 assert_eq!(get_str_vec[1], "b");
817 assert_eq!(get_str_vec[2], "c");
818}
819
820#[test]
821fn test_compound_tag_nested_compound_tag_vec() {
822 let mut compound_tag = CompoundTag::new();
823 let mut insert_nested_compound_tag_1 = CompoundTag::new();
824 let mut insert_nested_compound_tag_2 = CompoundTag::new();
825
826 insert_nested_compound_tag_1.insert_str("str", "test");
827 insert_nested_compound_tag_2.insert_i32("i32", 222333111);
828
829 let insert_nested_compound_tag_vec =
830 vec![insert_nested_compound_tag_1, insert_nested_compound_tag_2];
831
832 compound_tag.insert_compound_tag_vec("nested_compound_tag_vec", insert_nested_compound_tag_vec);
833
834 let get_nested_compound_tag_vec = compound_tag
835 .get_compound_tag_vec("nested_compound_tag_vec")
836 .unwrap();
837
838 let get_nested_compound_tag_1 = get_nested_compound_tag_vec[0];
839 let get_nested_compound_tag_2 = get_nested_compound_tag_vec[1];
840
841 assert_eq!(get_nested_compound_tag_1.get_str("str").unwrap(), "test");
842 assert_eq!(get_nested_compound_tag_2.get_i32("i32").unwrap(), 222333111);
843}
844
845#[test]
846fn test_servers_fmt() {
847 use crate::decode::read_compound_tag;
848 use std::io::Cursor;
849
850 let mut cursor = Cursor::new(include_bytes!("../test/binary/servers.dat").to_vec());
851 let root_tag = read_compound_tag(&mut cursor).unwrap();
852
853 assert_eq!(
854 &format!("{}", root_tag),
855 include_str!("../test/text/servers.snbt")
856 );
857 assert_eq!(
858 &format!("{:?}", root_tag),
859 include_str!("../test/text/servers.txt")
860 );
861}
862
863#[test]
864fn test_hello_world_fmt() {
865 use crate::decode::read_compound_tag;
866 use std::io::Cursor;
867
868 let mut cursor = Cursor::new(include_bytes!("../test/binary/hello_world.dat").to_vec());
869 let root_tag = read_compound_tag(&mut cursor).unwrap();
870
871 assert_eq!(
872 &format!("{}", root_tag),
873 include_str!("../test/text/hello_world.snbt")
874 );
875 assert_eq!(
876 &format!("{:?}", root_tag),
877 include_str!("../test/text/hello_world.txt")
878 );
879}
880
881#[test]
882fn test_player_fmt() {
883 use crate::decode::read_gzip_compound_tag;
884 use std::io::Cursor;
885
886 let mut cursor = Cursor::new(include_bytes!("../test/binary/player.dat").to_vec());
887 let root_tag = read_gzip_compound_tag(&mut cursor).unwrap();
888
889 assert_eq!(
890 &format!("{}", root_tag),
891 include_str!("../test/text/player.snbt")
892 );
893 assert_eq!(
894 &format!("{:?}", root_tag),
895 include_str!("../test/text/player.txt")
896 );
897}
898
899#[test]
900fn test_level_fmt() {
901 use crate::decode::read_gzip_compound_tag;
902 use std::io::Cursor;
903
904 let mut cursor = Cursor::new(include_bytes!("../test/binary/level.dat").to_vec());
905 let root_tag = read_gzip_compound_tag(&mut cursor).unwrap();
906
907 assert_eq!(
908 &format!("{}", root_tag),
909 include_str!("../test/text/level.snbt")
910 );
911 assert_eq!(
912 &format!("{:?}", root_tag),
913 include_str!("../test/text/level.txt")
914 );
915}
916
917#[test]
918fn test_is_empty() {
919 let mut compound_tag = CompoundTag::new();
920 assert!(compound_tag.is_empty());
921
922 compound_tag.insert_i32("test", 123);
923 assert!(!compound_tag.is_empty());
924}
925
926#[test]
927fn test_contains_key() {
928 let mut compound_tag = CompoundTag::new();
929 assert!(!compound_tag.contains_key("test"));
930
931 compound_tag.insert_i32("test", 123);
932 assert!(compound_tag.contains_key("test"));
933 assert!(!compound_tag.contains_key("test2"));
934}
935
936#[test]
937fn test_iter() {
938 let mut compound: CompoundTag = vec![
940 ("test1", Tag::Int(1)),
941 ("test2", Tag::Int(2)),
942 ("test3", Tag::Int(3)),
943 ]
944 .into_iter()
945 .collect();
946
947 {
949 let mut iter = compound.iter().map(|(name, tag)| {
950 (
951 name.as_str(),
952 match tag {
953 Tag::Int(value) => *value,
954 _ => panic!(),
955 },
956 )
957 });
958 assert_eq!(iter.next(), Some(("test1", 1)));
959 assert_eq!(iter.next(), Some(("test2", 2)));
960 assert_eq!(iter.next(), Some(("test3", 3)));
961 assert_eq!(iter.next(), None);
962 }
963
964 for (name, tag) in compound.iter_mut() {
966 if name == "test2" {
967 match tag {
968 Tag::Int(value) => *value = 10,
969 _ => panic!(),
970 }
971 }
972 }
973
974 {
976 let mut iter = compound.into_iter().map(|(name, tag)| {
977 (
978 name,
979 match tag {
980 Tag::Int(value) => value,
981 _ => panic!(),
982 },
983 )
984 });
985 assert_eq!(iter.next(), Some((String::from("test1"), 1)));
986 assert_eq!(iter.next(), Some((String::from("test2"), 10)));
987 assert_eq!(iter.next(), Some((String::from("test3"), 3)));
988 assert_eq!(iter.next(), None);
989 }
990}