1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#![deny(missing_docs)]
//! This crate allows reading and writing minecraft NBT (Named Binary Tag) data

use std::fmt::LowerHex;

pub mod de;
pub mod ser;

pub mod reader;

pub mod writer;

pub mod error;

pub mod version;

pub mod datatypes;

pub mod macros;

mod nbt_implementation;

#[cfg(test)]
mod tests;

pub mod traits;

/// type cast to give the NbtValue type id and undestandable name
#[repr(u8)]
#[allow(missing_docs)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum NbtTypeId {
    End = 0,
    Byte = 1,
    Short = 2,
    Int = 3,
    Long = 4,
    Float = 5,
    Double = 6,
    ByteArray = 7,
    String = 8,
    List = 9,
    Compound = 10,
    IntArray = 11,
    LongArray = 12,
}
impl TryFrom<u8> for NbtTypeId {
    type Error = crate::error::Error;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(NbtTypeId::End),
            1 => Ok(NbtTypeId::Byte),
            2 => Ok(NbtTypeId::Short),
            3 => Ok(NbtTypeId::Int),
            4 => Ok(NbtTypeId::Long),
            5 => Ok(NbtTypeId::Float),
            6 => Ok(NbtTypeId::Double),
            7 => Ok(NbtTypeId::ByteArray),
            8 => Ok(NbtTypeId::String),
            9 => Ok(NbtTypeId::List),
            10 => Ok(NbtTypeId::Compound),
            11 => Ok(NbtTypeId::IntArray),
            12 => Ok(NbtTypeId::LongArray),
            13.. => Err(error::Error::Message(format!("Failed to convert tag id('{value}') into tag")))
        }
    }
}

impl std::fmt::Display for NbtTypeId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{}", *self as u8))
    }
}
impl LowerHex for NbtTypeId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{:x}", *self as u8))
    }
}

/// The id of the current nbt version
///
/// # Info
///
/// this number is according to [this article](https://minecraft.fandom.com/wiki/NBT_format#History)
pub const NBT_VERSION: i32 = 19133;

pub mod nbt_value;
pub use nbt_value::NbtValue;
pub use nbt_value::to_nbt_value;

macro_rules! assert_return_IEEE754 {
    ($v0:expr, $v1:expr) => {
        if $v0 != $v1 {
            if $v0.is_nan() && $v1.is_nan() { return true }
            println!("Value {:?} and {:?} are not equal", $v0, $v1);
            dbg!(false)
        } else { true }
    };
}
macro_rules! assert_return {
    ($v0:expr, $v1:expr) => {
        if $v0 != $v1 {
            println!("Value {:?} and {:?} are not equal", $v0, $v1);
            dbg!(false)
        } else { true }
    };
}
impl PartialEq for NbtValue {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Byte(v0), Self::Byte(v1)) => assert_return!(v0, v1),
            (Self::Short(v0), Self::Short(v1)) => assert_return!(v0, v1),
            (Self::Int(v0), Self::Int(v1)) => assert_return!(v0, v1),
            (Self::Long(v0), Self::Long(v1)) => assert_return!(v0, v1),
            (Self::Float(v0), Self::Float(v1)) => assert_return_IEEE754!(v0, v1),
            (Self::Double(v0), Self::Double(v1)) => assert_return_IEEE754!(v0, v1),
            (Self::String(v0), Self::String(v1)) => assert_return!(v0, v1),
            (Self::ByteArray(v0), Self::ByteArray(v1)) => assert_return!(v0, v1),
            (Self::IntArray(v0), Self::IntArray(v1)) => assert_return!(v0, v1),
            (Self::LongArray(v0), Self::LongArray(v1)) => assert_return!(v0, v1),
            (Self::List(v0), Self::List(v1)) => assert_return!(v0, v1),
            (Self::Compound(_name0, v0), Self::Compound(_name1, v1)) => {
                if v0.len() != v1.len() { return dbg!(false) }
                for value in v0 {
                    if !v1.contains_key(value.0) { return dbg!(false) }
                    if value.1 != v1.get(value.0).unwrap() { return dbg!(false) }
                }
                true
            }
            _ => dbg!(false)
        }
    }
}