1use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5pub(crate) const MAGIC: &str = "_nbt_array_type";
6pub(crate) const MAGIC_BYTE_ARRAY: &str = "_nbt_byte_array";
7pub(crate) const MAGIC_INT_ARRAY: &str = "_nbt_int_array";
8pub(crate) const MAGIC_LONG_ARRAY: &str = "_nbt_long_array";
9
10macro_rules! impl_array_type {
11 ($(#[$meta:meta])* $mod_name:ident, $struct_name:ident, $magic:ident) => {
12 $(#[$meta])*
13 #[repr(transparent)]
14 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
15 pub struct $struct_name<T>(pub T);
16
17 $(#[$meta])*
18 pub mod $mod_name {
21 use serde::{Serialize, Serializer, Deserialize, Deserializer, de::{VariantAccess, EnumAccess, Visitor}};
22 use std::marker::PhantomData;
23
24 pub fn serialize<T: Serialize, S: Serializer>(
25 value: &T,
26 serializer: S,
27 ) -> Result<S::Ok, S::Error> {
28 serializer.serialize_newtype_struct(super::$magic, value)
30 }
31 pub fn deserialize<'de, T: Deserialize<'de>, D: Deserializer<'de>>(
32 deserializer: D,
33 ) -> Result<T, D::Error> {
34 struct V<T>(PhantomData<T>);
37 impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
38 type Value = T;
39
40 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
41 formatter.write_str(stringify!(a $struct_name))
42 }
43 fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> {
44 let (name, inner): (&str, _) = data.variant()?;
45
46 if name != super::$magic {
47 return Err(serde::de::Error::unknown_variant(
48 name,
49 &[super::MAGIC_BYTE_ARRAY, super::MAGIC_INT_ARRAY, super::MAGIC_LONG_ARRAY],
50 ));
51 }
52
53 inner.newtype_variant()
54 }
55 }
56 deserializer.deserialize_enum(super::MAGIC, &[], V(PhantomData))
57 }
58 }
59
60 impl<T: Serialize> Serialize for $struct_name<T>
61 {
62 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
63 $mod_name::serialize(&self.0, serializer)
64 }
65 }
66 impl<'de, T: Deserialize<'de>> Deserialize<'de> for $struct_name<T>
67 {
68 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
69 $mod_name::deserialize(deserializer).map($struct_name)
70 }
71 }
72 };
73}
74
75impl_array_type! {
76 byte_array, ByteArray, MAGIC_BYTE_ARRAY
78}
79impl_array_type! {
80 int_array, IntArray, MAGIC_INT_ARRAY
82}
83impl_array_type! {
84 long_array, LongArray, MAGIC_LONG_ARRAY
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::{tag::Tag, to_writer};
92 use serde::Serialize;
93
94 #[test]
95 fn test_byte_array() {
96 #[derive(Serialize)]
97 struct Test {
98 #[serde(with = "byte_array")]
99 bytes: Vec<u8>,
100 }
101
102 const BYTES: [u8; 5] = [1, 2, 3, 4, 5];
103 let mut buffer = Vec::new();
104
105 let bytes_written = to_writer(
106 &mut buffer,
107 &Test {
108 bytes: BYTES.to_vec(),
109 },
110 )
111 .unwrap();
112
113 assert_eq!(bytes_written, buffer.len(), "written bytes doesnt match");
114 #[rustfmt::skip]
115 assert_eq!(
116 buffer,
117 vec![
118 Tag::Compound as u8,
119 Tag::ByteArray as u8,
120 0, 5,
121 b'b', b'y', b't', b'e', b's',
122 0, 0, 0, 5,
123 1,
124 2,
125 3,
126 4,
127 5,
128 0
129 ]
130 );
131 }
132
133 #[test]
134 fn test_int_array() {
135 #[derive(Serialize)]
136 struct Test {
137 bytes: IntArray<Vec<u8>>,
138 }
139
140 const BYTES: [u8; 4] = [1, 2, 3, 4];
141 let mut buffer = Vec::new();
142
143 let bytes_written = to_writer(
144 &mut buffer,
145 &Test {
146 bytes: IntArray(BYTES.to_vec()),
147 },
148 )
149 .unwrap();
150
151 assert_eq!(bytes_written, buffer.len(), "written bytes doesnt match");
152 #[rustfmt::skip]
153 assert_eq!(
154 buffer,
155 vec![
156 Tag::Compound as u8,
157 Tag::IntArray as u8,
158 0, 5,
159 b'b', b'y', b't', b'e', b's',
160 0, 0, 0, 4,
161 0, 0, 0, 1,
162 0, 0, 0, 2,
163 0, 0, 0, 3,
164 0, 0, 0, 4,
165 0
166 ]
167 );
168 }
169
170 #[test]
171 fn test_long_array() {
172 #[derive(Serialize)]
173 struct Test {
174 bytes: LongArray<Vec<u8>>,
175 }
176
177 const BYTES: [u8; 4] = [1, 2, 3, 4];
178 let mut buffer = Vec::new();
179
180 let bytes_written = to_writer(
181 &mut buffer,
182 &Test {
183 bytes: LongArray(BYTES.to_vec()),
184 },
185 )
186 .unwrap();
187
188 assert_eq!(bytes_written, buffer.len(), "written bytes doesnt match");
189 #[rustfmt::skip]
190 assert_eq!(
191 buffer,
192 vec![
193 Tag::Compound as u8,
194 Tag::LongArray as u8,
195 0, 5,
196 b'b', b'y', b't', b'e', b's',
197 0, 0, 0, 4,
198 0, 0, 0, 0, 0, 0, 0, 1,
199 0, 0, 0, 0, 0, 0, 0, 2,
200 0, 0, 0, 0, 0, 0, 0, 3,
201 0, 0, 0, 0, 0, 0, 0, 4,
202 0
203 ]
204 );
205 }
206}