Skip to content

Commit 448cf26

Browse files
committed
macros: Copy from utils
Signed-off-by: Enrique Llorente <[email protected]>
1 parent 9bc9db7 commit 448cf26

File tree

5 files changed

+459
-26
lines changed

5 files changed

+459
-26
lines changed

src/error.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ impl From<String> for DecodeError {
5353
}
5454
}
5555

56+
impl From<std::string::FromUtf8Error> for DecodeError {
57+
fn from(err: std::string::FromUtf8Error) -> Self {
58+
Self {
59+
msg: format!("Invalid UTF-8 sequence: {}", err),
60+
}
61+
}
62+
}
63+
5664
impl std::fmt::Display for DecodeError {
5765
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5866
write!(f, "{}", self.msg)
@@ -61,6 +69,26 @@ impl std::fmt::Display for DecodeError {
6169

6270
impl std::error::Error for DecodeError {}
6371

72+
impl DecodeError {
73+
pub fn invalid_mac_address(received: usize) -> Self {
74+
Self{
75+
msg: format!("Invalid MAC address. Expected 6 bytes, received {received} bytes"),
76+
}
77+
}
78+
79+
pub fn invalid_ip_address(received: usize) -> Self {
80+
Self{
81+
msg: format!("Invalid IP address. Expected 4 or 16 bytes, received {received} bytes"),
82+
}
83+
}
84+
85+
pub fn invalid_number(expected: usize, received: usize) -> Self {
86+
Self{
87+
msg: format!("Invalid number. Expected {expected} bytes, received {received} bytes"),
88+
}
89+
}
90+
}
91+
6492
#[derive(Debug, PartialEq, Eq, Clone)]
6593
#[non_exhaustive]
6694
pub struct ErrorBuffer<T> {
@@ -252,8 +280,7 @@ mod tests {
252280
#[test]
253281
fn parse_nack() {
254282
// SAFETY: value is non-zero.
255-
const ERROR_CODE: NonZeroI32 =
256-
NonZeroI32::new(-1234).unwrap();
283+
const ERROR_CODE: NonZeroI32 = NonZeroI32::new(-1234).unwrap();
257284
let mut bytes = vec![0, 0, 0, 0];
258285
NativeEndian::write_i32(&mut bytes, ERROR_CODE.get());
259286
let msg = ErrorBuffer::new_checked(&bytes)

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,9 @@ pub use self::message::*;
267267

268268
pub mod constants;
269269
pub use self::constants::*;
270+
271+
pub mod parsers;
272+
pub use self::parsers::*;
273+
274+
#[macro_use]
275+
mod macros;

src/macros.rs

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
#[macro_export(local_inner_macros)]
4+
macro_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, i8, $offset:expr) => {
41+
pub fn $name(&self) -> i8 {
42+
self.buffer.as_ref()[$offset]
43+
}
44+
};
45+
($name:ident, i16, $offset:expr) => {
46+
pub fn $name(&self) -> i16 {
47+
use $crate::byteorder::{ByteOrder, NativeEndian};
48+
NativeEndian::read_i16(&self.buffer.as_ref()[$offset])
49+
}
50+
};
51+
($name:ident, i32, $offset:expr) => {
52+
pub fn $name(&self) -> i32 {
53+
use $crate::byteorder::{ByteOrder, NativeEndian};
54+
NativeEndian::read_i32(&self.buffer.as_ref()[$offset])
55+
}
56+
};
57+
($name:ident, i64, $offset:expr) => {
58+
pub fn $name(&self) -> i64 {
59+
use $crate::byteorder::{ByteOrder, NativeEndian};
60+
NativeEndian::read_i64(&self.buffer.as_ref()[$offset])
61+
}
62+
};
63+
}
64+
65+
#[macro_export(local_inner_macros)]
66+
macro_rules! setter {
67+
($buffer: ident, $name:ident, slice, $offset:expr) => {
68+
impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> $buffer<&'a mut T> {
69+
$crate::pastey::item! {
70+
pub fn [<$name _mut>](&mut self) -> &mut [u8] {
71+
&mut self.buffer.as_mut()[$offset]
72+
}
73+
}
74+
}
75+
};
76+
($buffer: ident, $name:ident, $ty:tt, $offset:expr) => {
77+
impl<'a, T: AsRef<[u8]> + AsMut<[u8]>> $buffer<T> {
78+
setter!($name, $ty, $offset);
79+
}
80+
};
81+
($name:ident, u8, $offset:expr) => {
82+
$crate::pastey::item! {
83+
pub fn [<set_ $name>](&mut self, value: u8) {
84+
self.buffer.as_mut()[$offset] = value;
85+
}
86+
}
87+
};
88+
($name:ident, u16, $offset:expr) => {
89+
$crate::pastey::item! {
90+
pub fn [<set_ $name>](&mut self, value: u16) {
91+
use $crate::byteorder::{ByteOrder, NativeEndian};
92+
NativeEndian::write_u16(&mut self.buffer.as_mut()[$offset], value)
93+
}
94+
}
95+
};
96+
($name:ident, u32, $offset:expr) => {
97+
$crate::pastey::item! {
98+
pub fn [<set_ $name>](&mut self, value: u32) {
99+
use $crate::byteorder::{ByteOrder, NativeEndian};
100+
NativeEndian::write_u32(&mut self.buffer.as_mut()[$offset], value)
101+
}
102+
}
103+
};
104+
($name:ident, u64, $offset:expr) => {
105+
$crate::pastey::item! {
106+
pub fn [<set_ $name>](&mut self, value: u64) {
107+
use $crate::byteorder::{ByteOrder, NativeEndian};
108+
NativeEndian::write_u64(&mut self.buffer.as_mut()[$offset], value)
109+
}
110+
}
111+
};
112+
($name:ident, i8, $offset:expr) => {
113+
$crate::pastey::item! {
114+
pub fn [<set_ $name>](&mut self, value: i8) {
115+
self.buffer.as_mut()[$offset] = value;
116+
}
117+
}
118+
};
119+
($name:ident, i16, $offset:expr) => {
120+
$crate::pastey::item! {
121+
pub fn [<set_ $name>](&mut self, value: i16) {
122+
use $crate::byteorder::{ByteOrder, NativeEndian};
123+
NativeEndian::write_i16(&mut self.buffer.as_mut()[$offset], value)
124+
}
125+
}
126+
};
127+
($name:ident, i32, $offset:expr) => {
128+
$crate::pastey::item! {
129+
pub fn [<set_ $name>](&mut self, value: i32) {
130+
use $crate::byteorder::{ByteOrder, NativeEndian};
131+
NativeEndian::write_i32(&mut self.buffer.as_mut()[$offset], value)
132+
}
133+
}
134+
};
135+
($name:ident, i64, $offset:expr) => {
136+
$crate::pastey::item! {
137+
pub fn [<set_ $name>](&mut self, value: i64) {
138+
use $crate::byteorder::{ByteOrder, NativeEndian};
139+
NativeEndian::write_i64(&mut self.buffer.as_mut()[$offset], value)
140+
}
141+
}
142+
};
143+
}
144+
145+
#[macro_export(local_inner_macros)]
146+
macro_rules! buffer {
147+
($name:ident($buffer_len:expr) { $($field:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {
148+
buffer!($name { $($field: ($ty, $offset),)* });
149+
buffer_check_length!($name($buffer_len));
150+
};
151+
152+
($name:ident { $($field:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {
153+
buffer_common!($name);
154+
fields!($name {
155+
$($field: ($ty, $offset),)*
156+
});
157+
};
158+
159+
($name:ident, $buffer_len:expr) => {
160+
buffer_common!($name);
161+
buffer_check_length!($name($buffer_len));
162+
};
163+
164+
($name:ident) => {
165+
buffer_common!($name);
166+
};
167+
}
168+
169+
#[macro_export(local_inner_macros)]
170+
macro_rules! fields {
171+
($buffer:ident { $($name:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {
172+
$(
173+
getter!($buffer, $name, $ty, $offset);
174+
)*
175+
176+
$(
177+
setter!($buffer, $name, $ty, $offset);
178+
)*
179+
}
180+
}
181+
182+
#[macro_export]
183+
macro_rules! buffer_check_length {
184+
($name:ident($buffer_len:expr)) => {
185+
impl<T: AsRef<[u8]>> $name<T> {
186+
pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {
187+
let packet = Self::new(buffer);
188+
packet.check_buffer_length()?;
189+
Ok(packet)
190+
}
191+
192+
fn check_buffer_length(&self) -> Result<(), DecodeError> {
193+
let len = self.buffer.as_ref().len();
194+
if len < $buffer_len {
195+
Err(DecodeError::InvalidBuffer {
196+
name: stringify!($name),
197+
received: len,
198+
minimum_length: $buffer_len,
199+
})
200+
} else {
201+
Ok(())
202+
}
203+
}
204+
}
205+
};
206+
}
207+
208+
#[macro_export]
209+
macro_rules! buffer_common {
210+
($name:ident) => {
211+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
212+
pub struct $name<T> {
213+
buffer: T,
214+
}
215+
216+
impl<T: AsRef<[u8]>> $name<T> {
217+
pub fn new(buffer: T) -> Self {
218+
Self { buffer }
219+
}
220+
221+
pub fn into_inner(self) -> T {
222+
self.buffer
223+
}
224+
}
225+
226+
impl<'a, T: AsRef<[u8]> + ?Sized> $name<&'a T> {
227+
pub fn inner(&self) -> &'a [u8] {
228+
&self.buffer.as_ref()[..]
229+
}
230+
}
231+
232+
impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> $name<&'a mut T> {
233+
pub fn inner_mut(&mut self) -> &mut [u8] {
234+
&mut self.buffer.as_mut()[..]
235+
}
236+
}
237+
};
238+
}

src/message.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -96,30 +96,31 @@ where
9696
.context("failed parsing NetlinkHeader")?;
9797

9898
let bytes = buf.payload();
99-
let payload =
100-
match header.message_type {
101-
NLMSG_ERROR => {
102-
let msg = ErrorBuffer::new_checked(&bytes)
103-
.and_then(|buf| ErrorMessage::parse(&buf))
104-
.context("failed parsing NLMSG_ERROR")?;
105-
Error(msg)
106-
}
107-
NLMSG_NOOP => Noop,
108-
NLMSG_DONE => {
109-
let msg = DoneBuffer::new_checked(&bytes)
110-
.and_then(|buf| DoneMessage::parse(&buf))
111-
.context("failed parsing NLMSG_DONE")?;
112-
Done(msg)
113-
}
114-
NLMSG_OVERRUN => Overrun(bytes.to_vec()),
115-
message_type => match I::deserialize(&header, bytes) {
116-
Err(e) => return Err(format!(
99+
let payload = match header.message_type {
100+
NLMSG_ERROR => {
101+
let msg = ErrorBuffer::new_checked(&bytes)
102+
.and_then(|buf| ErrorMessage::parse(&buf))
103+
.context("failed parsing NLMSG_ERROR")?;
104+
Error(msg)
105+
}
106+
NLMSG_NOOP => Noop,
107+
NLMSG_DONE => {
108+
let msg = DoneBuffer::new_checked(&bytes)
109+
.and_then(|buf| DoneMessage::parse(&buf))
110+
.context("failed parsing NLMSG_DONE")?;
111+
Done(msg)
112+
}
113+
NLMSG_OVERRUN => Overrun(bytes.to_vec()),
114+
message_type => match I::deserialize(&header, bytes) {
115+
Err(e) => {
116+
return Err(format!(
117117
"Failed to parse message with type {message_type}: {e}"
118118
)
119-
.into()),
120-
Ok(inner_msg) => InnerMessage(inner_msg),
121-
},
122-
};
119+
.into())
120+
}
121+
Ok(inner_msg) => InnerMessage(inner_msg),
122+
},
123+
};
123124
Ok(NetlinkMessage { header, payload })
124125
}
125126
}
@@ -240,8 +241,7 @@ mod tests {
240241
#[test]
241242
fn test_error() {
242243
// SAFETY: value is non-zero.
243-
const ERROR_CODE: NonZeroI32 =
244-
NonZeroI32::new(-8765).unwrap();
244+
const ERROR_CODE: NonZeroI32 = NonZeroI32::new(-8765).unwrap();
245245

246246
let header = NetlinkHeader::default();
247247
let error_msg = ErrorMessage {

0 commit comments

Comments
 (0)