Skip to main content

netlink_packet_utils/
macros.rs

1// SPDX-License-Identifier: MIT
2
3#[macro_export(local_inner_macros)]
4macro_rules! getter {
5    ($buffer: ident, $name:ident, slice, $offset:expr) => {
6        impl<'a, T: AsRef<[u8]> + ?Sized> $buffer<&'a T> {
7            pub fn $name(&self) -> &'a [u8] {
8                &self.buffer.as_ref()[$offset]
9            }
10        }
11    };
12    ($buffer: ident, $name:ident, $ty:tt, $offset:expr) => {
13        impl<'a, T: AsRef<[u8]>> $buffer<T> {
14            getter!($name, $ty, $offset);
15        }
16    };
17    ($name:ident, u8, $offset:expr) => {
18        pub fn $name(&self) -> u8 {
19            self.buffer.as_ref()[$offset]
20        }
21    };
22    ($name:ident, u16, $offset:expr) => {
23        pub fn $name(&self) -> u16 {
24            use $crate::byteorder::{ByteOrder, NativeEndian};
25            NativeEndian::read_u16(&self.buffer.as_ref()[$offset])
26        }
27    };
28    ($name:ident, u32, $offset:expr) => {
29        pub fn $name(&self) -> u32 {
30            use $crate::byteorder::{ByteOrder, NativeEndian};
31            NativeEndian::read_u32(&self.buffer.as_ref()[$offset])
32        }
33    };
34    ($name:ident, u64, $offset:expr) => {
35        pub fn $name(&self) -> u64 {
36            use $crate::byteorder::{ByteOrder, NativeEndian};
37            NativeEndian::read_u64(&self.buffer.as_ref()[$offset])
38        }
39    };
40    ($name:ident, u128, $offset:expr) => {
41        pub fn $name(&self) -> u128 {
42            use $crate::byteorder::{ByteOrder, NativeEndian};
43            NativeEndian::read_u128(&self.buffer.as_ref()[$offset])
44        }
45    };
46    ($name:ident, i8, $offset:expr) => {
47        pub fn $name(&self) -> i8 {
48            self.buffer.as_ref()[$offset]
49        }
50    };
51    ($name:ident, i16, $offset:expr) => {
52        pub fn $name(&self) -> i16 {
53            use $crate::byteorder::{ByteOrder, NativeEndian};
54            NativeEndian::read_i16(&self.buffer.as_ref()[$offset])
55        }
56    };
57    ($name:ident, i32, $offset:expr) => {
58        pub fn $name(&self) -> i32 {
59            use $crate::byteorder::{ByteOrder, NativeEndian};
60            NativeEndian::read_i32(&self.buffer.as_ref()[$offset])
61        }
62    };
63    ($name:ident, i64, $offset:expr) => {
64        pub fn $name(&self) -> i64 {
65            use $crate::byteorder::{ByteOrder, NativeEndian};
66            NativeEndian::read_i64(&self.buffer.as_ref()[$offset])
67        }
68    };
69    ($name:ident, i128, $offset:expr) => {
70        pub fn $name(&self) -> i128 {
71            use $crate::byteorder::{ByteOrder, NativeEndian};
72            NativeEndian::read_i128(&self.buffer.as_ref()[$offset])
73        }
74    };
75}
76
77#[macro_export(local_inner_macros)]
78macro_rules! setter {
79    ($buffer: ident, $name:ident, slice, $offset:expr) => {
80        impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> $buffer<&'a mut T> {
81            $crate::paste::item! {
82                pub fn [<$name _mut>](&mut self) -> &mut [u8] {
83                    &mut self.buffer.as_mut()[$offset]
84                }
85            }
86        }
87    };
88    ($buffer: ident, $name:ident, $ty:tt, $offset:expr) => {
89        impl<'a, T: AsRef<[u8]> + AsMut<[u8]>> $buffer<T> {
90            setter!($name, $ty, $offset);
91        }
92    };
93    ($name:ident, u8, $offset:expr) => {
94        $crate::paste::item! {
95            pub fn [<set_ $name>](&mut self, value: u8) {
96                self.buffer.as_mut()[$offset] = value;
97            }
98        }
99    };
100    ($name:ident, u16, $offset:expr) => {
101        $crate::paste::item! {
102            pub fn [<set_ $name>](&mut self, value: u16) {
103                use $crate::byteorder::{ByteOrder, NativeEndian};
104                NativeEndian::write_u16(&mut self.buffer.as_mut()[$offset], value)
105            }
106        }
107    };
108    ($name:ident, u32, $offset:expr) => {
109        $crate::paste::item! {
110            pub fn [<set_ $name>](&mut self, value: u32) {
111                use $crate::byteorder::{ByteOrder, NativeEndian};
112                NativeEndian::write_u32(&mut self.buffer.as_mut()[$offset], value)
113            }
114        }
115    };
116    ($name:ident, u64, $offset:expr) => {
117        $crate::paste::item! {
118            pub fn [<set_ $name>](&mut self, value: u64) {
119                use $crate::byteorder::{ByteOrder, NativeEndian};
120                NativeEndian::write_u64(&mut self.buffer.as_mut()[$offset], value)
121            }
122        }
123    };
124    ($name:ident, u128, $offset:expr) => {
125        $crate::paste::item! {
126            pub fn [<set_ $name>](&mut self, value: u128) {
127                use $crate::byteorder::{ByteOrder, NativeEndian};
128                NativeEndian::write_u128(&mut self.buffer.as_mut()[$offset], value)
129            }
130        }
131    };
132    ($name:ident, i8, $offset:expr) => {
133        $crate::paste::item! {
134            pub fn [<set_ $name>](&mut self, value: i8) {
135                self.buffer.as_mut()[$offset] = value;
136            }
137        }
138    };
139    ($name:ident, i16, $offset:expr) => {
140        $crate::paste::item! {
141            pub fn [<set_ $name>](&mut self, value: i16) {
142                use $crate::byteorder::{ByteOrder, NativeEndian};
143                NativeEndian::write_i16(&mut self.buffer.as_mut()[$offset], value)
144            }
145        }
146    };
147    ($name:ident, i32, $offset:expr) => {
148        $crate::paste::item! {
149            pub fn [<set_ $name>](&mut self, value: i32) {
150                use $crate::byteorder::{ByteOrder, NativeEndian};
151                NativeEndian::write_i32(&mut self.buffer.as_mut()[$offset], value)
152            }
153        }
154    };
155    ($name:ident, i64, $offset:expr) => {
156        $crate::paste::item! {
157            pub fn [<set_ $name>](&mut self, value: i64) {
158                use $crate::byteorder::{ByteOrder, NativeEndian};
159                NativeEndian::write_i64(&mut self.buffer.as_mut()[$offset], value)
160            }
161        }
162    };
163    ($name:ident, i128, $offset:expr) => {
164        $crate::paste::item! {
165            pub fn [<set_ $name>](&mut self, value: i128) {
166                use $crate::byteorder::{ByteOrder, NativeEndian};
167                NativeEndian::write_i128(&mut self.buffer.as_mut()[$offset], value)
168            }
169        }
170    };
171}
172
173#[macro_export(local_inner_macros)]
174macro_rules! buffer {
175    ($name:ident($($buffer_len:expr)?) { $($field:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {
176        buffer_common!($name);
177        fields!($name {
178            $($field: ($ty, $offset),)*
179        });
180        buffer_check_length!($name $(, $buffer_len)?);
181    };
182
183    ($name:ident { $($field:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {
184        buffer_common!($name);
185        buffer_no_length!($name);
186        fields!($name {
187            $($field: ($ty, $offset),)*
188        });
189    };
190
191    ($name:ident, buffer_len:expr) => {
192        buffer_common!($name);
193        buffer_check_length!($name, $buffer_len);
194    };
195
196    ($name:ident) => {
197        buffer_common!($name);
198        buffer_no_length!($name);
199    };
200}
201
202#[macro_export(local_inner_macros)]
203macro_rules! fields {
204    ($buffer:ident { $($name:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {
205        $(
206            getter!($buffer, $name, $ty, $offset);
207        )*
208
209            $(
210                setter!($buffer, $name, $ty, $offset);
211            )*
212    }
213}
214
215#[macro_export]
216macro_rules! buffer_check_length {
217    ($name:ident) => {
218        impl<T: AsRef<[u8]>> $name<T> {
219            pub(crate) fn new_unchecked(buffer: T) -> Self {
220                Self { buffer }
221            }
222        }
223    };
224    ($name:ident, $buffer_len:expr) => {
225        impl<T: AsRef<[u8]>> $name<T> {
226            pub fn new(buffer: T) -> Result<Self, DecodeError> {
227                let packet = Self::new_unchecked(buffer);
228                packet.check_buffer_length()?;
229                Ok(packet)
230            }
231
232            pub(crate) fn new_unchecked(buffer: T) -> Self {
233                Self { buffer }
234            }
235
236            fn check_buffer_length(&self) -> Result<(), DecodeError> {
237                let len = self.buffer.as_ref().len();
238                if len < $buffer_len {
239                    Err(DecodeError::InvalidBufferLength {
240                        name: stringify!($name),
241                        len,
242                        buffer_len: $buffer_len,
243                    })
244                } else {
245                    Ok(())
246                }
247            }
248        }
249    };
250}
251
252#[macro_export]
253macro_rules! buffer_no_length {
254    ($name:ident) => {
255        impl<T: AsRef<[u8]>> $name<T> {
256            pub fn new(buffer: T) -> Self {
257                Self { buffer }
258            }
259        }
260    };
261}
262
263#[macro_export]
264macro_rules! buffer_common {
265    ($name:ident) => {
266        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
267        pub struct $name<T> {
268            buffer: T,
269        }
270
271        impl<T: AsRef<[u8]>> $name<T> {
272            pub fn into_inner(self) -> T {
273                self.buffer
274            }
275        }
276
277        impl<'a, T: AsRef<[u8]> + ?Sized> $name<&'a T> {
278            pub fn inner(&self) -> &'a [u8] {
279                &self.buffer.as_ref()[..]
280            }
281        }
282
283        impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> $name<&'a mut T> {
284            pub fn inner_mut(&mut self) -> &mut [u8] {
285                &mut self.buffer.as_mut()[..]
286            }
287        }
288    };
289}