mcproto_types/nbt.rs
1//! Named Binary Tag (NBT) values.
2//!
3//! This module wraps [`fastnbt::Value`] so complete NBT payloads can be encoded
4//! and decoded through [`TypeCodec`].
5
6use std::io::{Read, Write};
7
8use fastnbt::{DeOpts, SerOpts};
9use mcproto_codec::error::{CodecError, CodecKind, CodecOperation, InvalidEncodingReason};
10
11use crate::TypeCodec;
12
13/// A Minecraft network NBT (Named Binary Tag) value.
14///
15/// This is a thin wrapper around [`fastnbt::Value`]. Parsing and serialization
16/// are delegated directly to `fastnbt`. The wire format is network NBT, so the
17/// root compound name is omitted; like `fastnbt`, the root value must be an
18/// NBT compound.
19///
20/// # Examples
21///
22/// ```
23/// use fastnbt::nbt;
24/// use mcproto_types::{TypeCodec, nbt::Nbt};
25///
26/// let value = nbt!({
27/// "name": "minecraft:stone",
28/// "count": 1i8,
29/// });
30///
31/// let mut encoded = Vec::new();
32/// Nbt(value.clone()).encode(&mut encoded)?;
33///
34/// let mut input = encoded.as_slice();
35/// assert_eq!(Nbt::decode(&mut input)?, Nbt(value));
36/// assert!(input.is_empty());
37/// # Ok::<(), mcproto_codec::error::CodecError>(())
38/// ```
39#[derive(Debug, Clone, PartialEq)]
40pub struct Nbt(
41 /// The NBT value.
42 pub fastnbt::Value,
43);
44
45impl TypeCodec for Nbt {
46 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
47 fastnbt::to_writer_with_opts(writer, &self.0, SerOpts::network_nbt())
48 .map_err(|source| invalid_nbt(CodecOperation::Write, source))
49 }
50
51 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
52 fastnbt::from_reader_with_opts(reader, DeOpts::network_nbt())
53 .map(Self)
54 .map_err(|source| invalid_nbt(CodecOperation::Read, source))
55 }
56}
57
58fn invalid_nbt(operation: CodecOperation, source: fastnbt::error::Error) -> CodecError {
59 CodecError::invalid_encoding_for_operation_with_source(
60 CodecKind::Nbt,
61 operation,
62 0,
63 InvalidEncodingReason::InvalidNbt,
64 source,
65 )
66}