craftflow_nbt/
arrays.rs

1//! Provides a choice to serialize sequences as `ByteArray`, `IntArray` or `LongArray`.
2
3use 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		///
19		/// Use this with `#[serde(with = "..."]`
20		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                // use a newtype struct with a magic name to signal the serializer for special behaviour
29                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                // Tell the deserializer that we are expecting an enum variant with a magic name
35
36               	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	/// Allows to (de)serialize a sequence as a `ByteArray`.
77	byte_array, ByteArray, MAGIC_BYTE_ARRAY
78}
79impl_array_type! {
80	/// Allows to (de)serialize a sequence as an `IntArray`.
81	int_array, IntArray, MAGIC_INT_ARRAY
82}
83impl_array_type! {
84	/// Allows to (de)serialize a sequence as a `LongArray`.
85	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}