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
//! A library for encoding and decoding Minecraft's [Named Binary Tag] (NBT)
//! format.
//!
//! [Named Binary Tag]: https://minecraft.fandom.com/wiki/NBT_format
//!
//! # Examples
//!
//! Encode NBT data to its binary form. We are using the [`compound!`] macro to
//! conveniently construct [`Compound`] values.
//!
//! ```rust
//! use valence_nbt::{compound, to_binary_writer, List};
//!
//! let c = compound! {
//!     "byte" => 5_i8,
//!     "string" => "hello",
//!     "list_of_float" => List::Float(vec![
//!         3.1415,
//!         2.7182,
//!         1.4142
//!     ]),
//! };
//!
//! let mut buf = Vec::new();
//!
//! to_binary_writer(&mut buf, &c, "").unwrap();
//! ```
//!
//! Decode NBT data from its binary form.
//!
//! ```rust
//! use valence_nbt::{compound, from_binary_slice};
//!
//! let some_bytes = [10, 0, 0, 3, 0, 3, 105, 110, 116, 0, 0, 222, 173, 0];
//!
//! let expected_value = compound! {
//!     "int" => 0xdead
//! };
//!
//! let (nbt, root_name) = from_binary_slice(&mut some_bytes.as_slice()).unwrap();
//!
//! assert_eq!(nbt, expected_value);
//! assert_eq!(root_name, "");
//! ```
//!
//! # Features
//!
//! - `preserve_order`: Causes the order of fields in [`Compound`]s to be
//! preserved during insertion and deletion at a slight cost to performance.
//! The iterators on `Compound` can then implement [`DoubleEndedIterator`].

#![deny(unsafe_code)]

pub use compound::Compound;
pub use error::Error;
pub use from_binary_slice::from_binary_slice;
pub use to_binary_writer::to_binary_writer;
pub use value::{List, Value};

pub mod compound;
mod error;
mod from_binary_slice;
mod to_binary_writer;
pub mod value;

mod tag;
#[cfg(test)]
mod tests;

/// Maximum recursion depth to prevent overflowing the call stack.
const MAX_DEPTH: usize = 512;

type Result<T> = std::result::Result<T, Error>;

/// A convenience macro for constructing [`Compound`]s.
///
/// Key expressions must implement `Into<String>` while value expressions must
/// implement `Into<Value>`.
///
/// # Examples
///
/// ```
/// use valence_nbt::{compound, List};
///
/// let c = compound! {
///     "byte" => 123_i8,
///     "list_of_int" => List::Int(vec![3, -7, 5]),
///     "list_of_string" => List::String(vec![
///         "foo".to_owned(),
///         "bar".to_owned(),
///         "baz".to_owned()
///     ]),
///     "string" => "aé日",
///     "compound" => compound! {
///         "foo" => 1,
///         "bar" => 2,
///         "baz" => 3,
///     },
///     "int_array" => vec![5, -9, i32::MIN, 0, i32::MAX],
///     "byte_array" => vec![0_i8, 2, 3],
///     "long_array" => vec![123_i64, 456, 789],
/// };
///
/// println!("{c:?}");
/// ```
#[macro_export]
macro_rules! compound {
    ($($key:expr => $value:expr),* $(,)?) => {
        <$crate::Compound as ::std::iter::FromIterator<(::std::string::String, $crate::Value)>>::from_iter([
            $(
                (
                    ::std::convert::Into::<::std::string::String>::into($key),
                    ::std::convert::Into::<$crate::Value>::into($value)
                ),
            )*
        ])
    }
}