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*/