net_mc/packet/builder.rs
1// The following code was taken from https://github.com/feather-rs/feather/blob/main/feather/protocol/src/packets.rs which is licensed under Apache 2.0.
2// It was modified slightly to fit the needs of this crate.
3
4#[macro_export]
5macro_rules! user_type {
6 (VarInt) => {
7 i32
8 };
9 (VarIntPrefixedVec <$inner:ident>) => {
10 Vec<$inner>
11 };
12 (ShortPrefixedVec <$inner:ident>) => {
13 Vec<$inner>
14 };
15 (LengthInferredVecU8) => {
16 Vec<u8>
17 };
18 (Angle) => {
19 f32
20 };
21 ($typ:ty) => {
22 $typ
23 };
24}
25
26#[macro_export]
27macro_rules! user_type_convert_to_writeable {
28 (VarInt, $e:expr) => {
29 VarInt(*$e as i32)
30 };
31 (VarIntPrefixedVec <$inner:ident>, $e:expr) => {
32 VarIntPrefixedVec::from($e.as_slice())
33 };
34 (ShortPrefixedVec <$inner:ident>, $e:expr) => {
35 ShortPrefixedVec::from($e.as_slice())
36 };
37 (LengthInferredVecU8, $e:expr) => {
38 LengthInferredVecU8::from($e.as_slice())
39 };
40 (Angle, $e:expr) => {
41 Angle(*$e)
42 };
43 ($typ:ty, $e:expr) => {
44 $e
45 };
46}
47
48#[macro_export]
49macro_rules! packets {
50 (
51 $(
52 $packet:ident($id:expr) {
53 $(
54 $field:ident $typ:ident $(<$generics:ident>)?
55 );* $(;)?
56 } $(,)?
57 )*
58 ) => {
59 $(
60 use net_mc::types::*;
61 use net_mc::packet::*;
62
63 #[derive(Debug, Clone)]
64 pub struct $packet {
65 $(
66 pub $field: user_type!($typ $(<$generics>)?),
67 )*
68 }
69
70 impl Packet for $packet {
71 const ID: VarInt = VarInt($id);
72 }
73
74 #[allow(unused_imports, unused_variables)]
75 impl Decoder for $packet {
76 fn read_from(buffer: &mut impl std::io::Read) -> anyhow::Result<Self>
77 where
78 Self: Sized
79 {
80 use anyhow::Context as _;
81 $(
82 let $field = <$typ $(<$generics>)?>::read_from(buffer)
83 .context(concat!("failed to read field `", stringify!($field), "` of packet `", stringify!($packet), "`"))?
84 .into();
85 )*
86
87 Ok(Self {
88 $(
89 $field,
90 )*
91 })
92 }
93 }
94
95 #[allow(unused_variables)]
96 impl Encoder for $packet {
97 fn write_to(&self, w: &mut impl std::io::Write) -> anyhow::Result<()> {
98 $(
99 user_type_convert_to_writeable!($typ $(<$generics>)?, &self.$field).write_to(w)?;
100 )*
101 Ok(())
102 }
103 }
104 )*
105 };
106}
107
108#[macro_export]
109macro_rules! discriminant_to_literal {
110 (String, $discriminant:expr) => {
111 &*$discriminant
112 };
113 ($discriminant_type:ident, $discriminant:expr) => {
114 $discriminant.into()
115 };
116}
117
118#[macro_export]
119macro_rules! def_enum {
120 (
121 $ident:ident ($discriminant_type:ident) {
122 $(
123 $discriminant:literal = $variant:ident
124 $(
125 {
126 $(
127 $field:ident $typ:ident $(<$generics:ident>)?
128 );* $(;)?
129 }
130 )?
131 ),* $(,)?
132 }
133 ) => {
134 #[derive(Debug, Clone)]
135 pub enum $ident {
136 $(
137 $variant
138 $(
139 {
140 $(
141 $field: user_type!($typ $(<$generics>)?),
142 )*
143 }
144 )?,
145 )*
146 }
147
148 impl packet::Decoder for $ident {
149 fn read_from(buffer: &mut impl std::io::Read) -> anyhow::Result<Self>
150 where
151 Self: Sized
152 {
153 use anyhow::Context as _;
154 let discriminant = <$discriminant_type>::read_from(buffer)
155 .context(concat!("failed to read discriminant for enum type ", stringify!($ident)))?;
156
157 match discriminant_to_literal!($discriminant_type, discriminant) {
158 $(
159 $discriminant => {
160 $(
161 $(
162 let $field = <$typ $(<$generics>)?>::read(buffer, version)
163 .context(concat!("failed to read field `", stringify!($field),
164 "` of enum `", stringify!($ident), "::", stringify!($variant), "`"))?
165 .into();
166 )*
167 )?
168
169 Ok($ident::$variant $(
170 {
171 $(
172 $field,
173 )*
174 }
175 )?)
176 },
177 )*
178 _ => Err(anyhow::anyhow!(
179 concat!(
180 "no discriminant for enum `", stringify!($ident), "` matched value {:?}"
181 ), discriminant
182 ))
183 }
184 }
185 }
186
187 impl packet::Encoder for $ident {
188 fn write_to(&self, buffer: &mut impl std::io::Write) -> anyhow::Result<()> {
189 match self {
190 $(
191 $ident::$variant $(
192 {
193 $($field,)*
194 }
195 )? => {
196 let discriminant = <$discriminant_type>::from($discriminant);
197 discriminant.write_to(buffer)?;
198
199 $(
200 $(
201 user_type_convert_to_writeable!($typ $(<$generics>)?, $field).write(buffer, version)?;
202 )*
203 )?
204 }
205 )*
206 }
207 Ok(())
208 }
209 }
210 };
211}
212
213/*
214#[macro_export]
215macro_rules! packet_enum {
216 (
217 $ident:ident {
218 $($id:literal = $packet:ident),* $(,)?
219 }
220 ) => {
221 #[derive(Debug, Clone)]
222 pub enum $ident {
223 $(
224 $packet($packet),
225 )*
226 }
227
228 impl $ident {
229 /// Returns the packet ID of this packet.
230 pub fn id(&self) -> u32 {
231 match self {
232 $(
233 $ident::$packet(_) => $id,
234 )*
235 }
236 }
237 }
238
239 impl crate::Readable for $ident {
240 fn read_from(buffer: &mut ::std::io::Cursor<&[u8]>, version: crate::ProtocolVersion) -> anyhow::Result<Self>
241 where
242 Self: Sized
243 {
244 let packet_id = VarInt::read(buffer, version)?.0;
245 match packet_id {
246 $(
247 id if id == $id => Ok($ident::$packet($packet::read(buffer, version)?)),
248 )*
249 _ => Err(anyhow::anyhow!("unknown packet ID {}", packet_id)),
250 }
251 }
252 }
253
254 impl crate::Writeable for $ident {
255 fn write_to(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> {
256 VarInt(self.id() as i32).write(buffer, version)?;
257 match self {
258 $(
259 $ident::$packet(packet) => {
260 packet.write(buffer, version)?;
261 }
262 )*
263 }
264 Ok(())
265 }
266 }
267
268 $(
269 impl VariantOf<$ident> for $packet {
270 fn discriminant_id() -> u32 { $id }
271
272 #[allow(unreachable_patterns)]
273 fn destructure(e: $ident) -> Option<Self> {
274 match e {
275 $ident::$packet(p) => Some(p),
276 _ => None,
277 }
278 }
279 }
280
281 impl From<$packet> for $ident {
282 fn from(packet: $packet) -> Self {
283 $ident::$packet(packet)
284 }
285 }
286 )*
287 }
288}
289*/