1macro_rules! p9_message_struct {
6 ($( $num:literal $name:ident $($field_name:ident [$field_type:tt] )* ;)*) => {
7 $(
8 #[allow(dead_code)]
13 pub struct $name<'a> {
14 pub reader: super::SliceReader<'a>,
15 $(pub $field_name: p9_message_struct!(@to_type $field_type),)*
16 }
17
18 impl<'a> TryFrom<super::SliceReader<'a>> for $name<'a> {
20 type Error = lx::Error;
21
22 p9_message_struct!(@try_from $name $($field_name [$field_type])*);
23 }
24
25 impl<'a> std::fmt::Debug for $name<'a> {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.debug_struct(stringify!($name))
29 $(
30 .field(stringify!($field_name), &self.$field_name)
31 )*
32 .finish()
33 }
34 }
35 )*
36 };
37
38 (@to_type s) => { &'a lx::LxStr };
40 (@to_type n) => { &'a lx::LxStr };
41 (@to_type q) => { Qid };
42 (@to_type ns) => { super::NameIterator<'a> };
43 (@to_type qs) => { super::QidIterator<'a> };
44 (@to_type 2) => { u16 };
45 (@to_type 4) => { u32 };
46 (@to_type 8) => { u64 };
47
48 (@to_read $name:ident s) => { $name.string()? };
50 (@to_read $name:ident n) => { $name.name()? };
51 (@to_read $name:ident q) => { $name.qid()? };
52 (@to_read $name:ident ns) => { $name.names()? };
53 (@to_read $name:ident qs) => { $name.qids()? };
54 (@to_read $name:ident 2) => { $name.u16()? };
55 (@to_read $name:ident 4) => { $name.u32()? };
56 (@to_read $name:ident 8) => { $name.u64()? };
57
58 (@try_from $name:ident $($field_name:ident [$field_type:tt] )+) => {
60 fn try_from(mut reader: super::SliceReader<'a>) -> lx::Result<$name<'a>> {
61 $(
62 let $field_name = p9_message_struct!(@to_read reader $field_type);
63 )+
64 Ok($name {
65 reader,
66 $(
67 $field_name,
68 )+
69 })
70 }
71 };
72
73 (@try_from $name:ident) => {
76 fn try_from(reader: super::SliceReader<'a>) -> lx::Result<$name<'a>> {
77 Ok($name {
78 reader,
79 })
80 }
81 };
82}
83
84macro_rules! p9_message_enum {
86 ($( $num:literal $name:ident $($field_name:ident [$field_type:tt] )* ;)*) => {
87 #[expect(dead_code)]
88 #[derive(Debug)]
89 pub enum Plan9Message<'a> {
90 $($name($name<'a>),)*
91 }
92
93 impl<'a> Plan9Message<'a> {
94 pub fn read(message_type: u8, reader: super::SliceReader<'a>) -> lx::Result<Plan9Message<'a>> {
97 let message = match message_type {
98 $($num => Plan9Message::$name(reader.try_into()?),)*
99 _ => {
100 tracing::warn!(message_type, "[9P] Unhandled message type");
101 return Err(lx::Error::EINVAL)
102 }
103 };
104
105 Ok(message)
106 }
107 }
108 };
109}
110
111#[macro_export]
113macro_rules! p9_protocol_messages {
114 ($($contents:tt)*) => {
115 p9_message_struct!($($contents)*);
116 p9_message_enum!($($contents)*);
117 }
118}