fuse/request/
macros.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4/// Generates an enum that holds fuse operations and their arguments.
5macro_rules! fuse_operations {
6    ($( $opcode:ident $name:ident $($arg_name:ident : $arg_type:tt)* ; )*) => {
7        /// Represents a FUSE message and its arguments.
8        pub enum FuseOperation {
9            /// An operation where the header could be parsed, but the remainder of the message
10            /// could not.
11            Invalid,
12            $(
13                $name {
14                    $($arg_name: fuse_operations!(@to_type $arg_type),)*
15                },
16            )*
17        }
18
19        impl FuseOperation {
20            /// Create a FuseOperation for the specified opcode, reading the arguments from the
21            /// reader.
22            pub fn read(opcode: u32, mut reader: impl RequestReader) -> lx::Result<Self> {
23                let op = match opcode {
24                    $($opcode => {
25                        $(
26                            let $arg_name: fuse_operations!(@to_type $arg_type) = fuse_operations!(@to_read reader $arg_type);
27                        )*
28                        Self::$name {
29                            $(
30                                $arg_name,
31                            )*
32                        }
33                    },)*
34                    _ => {
35                        tracing::error!(opcode, "Invalid opcode");
36                        return Err(lx::Error::EINVAL)
37                    }
38                };
39
40                Ok(op)
41            }
42        }
43
44        impl std::fmt::Debug for FuseOperation {
45            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46                match self {
47                    FuseOperation::Invalid => f.write_str("Invalid"),
48                    $(
49                        FuseOperation::$name { $($arg_name,)* } => {
50                            let mut d = f.debug_struct(stringify!($name));
51                            $(
52                                fuse_operations!(@to_debug d $arg_name $arg_type);
53                            )*
54                            d.finish()
55                        }
56                    )*
57                }
58            }
59        }
60    };
61
62    // Convert type name to the field type.
63    (@to_type name) => { lx::LxString };
64    (@to_type str) => { lx::LxString };
65    (@to_type [u8; $arg:ident.$field:ident]) => { Box<[u8]> };
66    (@to_type [u8]) => { Box<[u8]> };
67    (@to_type $t:tt) => { $t };
68
69    // Convert type name to the associated reader method.
70    (@to_read $name:ident name) => { $name.name()? };
71    (@to_read $name:ident str) => { $name.string()? };
72    (@to_read $name:ident [u8]) => { $name.read_all()? };
73    (@to_read $name:ident [u8; $arg:ident.$field:ident]) => { $name.read_count($arg.$field as usize)? };
74    (@to_read $name:ident $t:tt) => { $name.read_type()? };
75
76    (@to_debug $debug:ident $name:ident [u8]) => { $debug.field(stringify!($name), &$name.len()) };
77    (@to_debug $debug:ident $name:ident [u8; $arg:ident.$field:ident]) => { $debug.field(stringify!($name), &$name.len()) };
78    (@to_debug $debug:ident $name:ident $t:tt) => { $debug.field(stringify!($name), $name); };
79}