smb_fscc/
info_classes.rs

1//! Framework for implementing FSCC Info Classes
2
3use binrw::{
4    meta::{ReadEndian, WriteEndian},
5    prelude::*,
6};
7
8/// Trait for file information types.
9/// This trait contains all types of all file info types and classes, specified in MS-FSCC.
10///
11/// It's role is to allow converting an instance of a file information type to a class,
12/// and to provide the class type from the file information type.
13pub trait FileInfoType:
14    Sized
15    + for<'a> BinRead<Args<'static> = (Self::Class,)>
16    + ReadEndian
17    + for<'a> BinWrite<Args<'static> = ()>
18    + WriteEndian
19    + std::fmt::Debug
20{
21    /// The class of the file information.
22    type Class;
23
24    /// Get the class of the file information.
25    fn class(&self) -> Self::Class;
26}
27
28/// An internal macro for generating a file class enums,
29/// for both the file information class, and information value.
30/// including a trait for the value types.
31macro_rules! file_info_classes {
32    (
33        $(#[doc = $docstring:literal])*
34        $svis:vis $name:ident {
35            $($vis:vis $field_name:ident = $cid:literal,)+
36        }
37    ) => {
38        #[allow(unused_imports)]
39        use binrw::prelude::*;
40        pastey::paste! {
41            /// Trait for inner values in
42            #[doc = concat!("[`", stringify!($name), "`][crate::", stringify!($name), "].")]
43            ///
44            /// This trait provides the `CLASS_ID` constant for each value type,
45            /// linking values to their information class IDs.
46            ///
47            /// _Auto-generated by the `file_info_classes!` macro_
48            pub trait [<$name Value>] :
49                TryFrom<$name, Error = $crate::SmbFsccError>
50                + Send + 'static
51                + Into<$name>
52                + for <'a> [<BinRead>]<Args<'a> = ()>
53                + for <'b> [<BinWrite>]<Args<'b> = ()>
54            {
55                const CLASS_ID: [<$name Class>];
56            }
57
58            /// Information class IDs for
59            #[doc = concat!("[`", stringify!($name), "`][crate::", stringify!($name), "]")]
60            ///
61            /// _Auto-generated by the `file_info_classes!` macro_
62            #[binrw::binrw]
63            #[derive(Debug, PartialEq, Eq, Clone, Copy)]
64            #[brw(repr(u8))]
65            $svis enum [<$name Class>] {
66                $(
67                    $vis [<$field_name Information>] = $cid,
68                )*
69            }
70
71            $(#[doc = $docstring])*
72            ///
73            /// See:
74            #[doc = concat!("- [`", stringify!([<$name Class>]), "`][crate::", stringify!([<$name Class>]), "] - class IDs")]
75            #[doc = concat!("- [`", stringify!([<$name Value>]), "`][crate::", stringify!([<$name Value>]), "] - value trait")]
76            ///
77            /// _Auto-generated by the `file_info_classes!` macro_
78            #[binrw::binrw]
79            #[derive(Debug, PartialEq, Eq)]
80            #[brw(little)]
81            #[br(import(c: [<$name Class>]))]
82            $svis enum $name {
83                $(
84                    #[br(pre_assert(matches!(c, [<$name Class>]::[<$field_name Information>])))]
85                    [<$field_name Information>]([<File $field_name Information>]),
86                )*
87            }
88
89            impl std::fmt::Display for [<$name Class>] {
90                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91                    match self {
92                        $(
93                            [<$name Class>]::[<$field_name Information>] => write!(f, stringify!([<$field_name Information>])),
94                        )*
95                    }
96                }
97            }
98
99            impl $crate::FileInfoType for $name {
100                type Class = [<$name Class>];
101                fn class(&self) -> Self::Class {
102                    match self {
103                        $(
104                            $name::[<$field_name Information>](_) => [<$name Class>]::[<$field_name Information>],
105                        )*
106                    }
107                }
108            }
109
110            $(
111                impl From<[<File $field_name Information>]> for $name {
112                    fn from(value: [<File $field_name Information>]) -> $name {
113                        $name::[<$field_name Information>](value)
114                    }
115                }
116
117                impl TryFrom<$name> for [<File $field_name Information>] {
118                    type Error = $crate::SmbFsccError;
119
120                    fn try_from(value: $name) -> Result<Self, Self::Error> {
121                        pub use $crate::FileInfoType;
122                        match value {
123                            $name::[<$field_name Information>](v) => Ok(v),
124                            _ => Err($crate::SmbFsccError::UnexpectedInformationType(stringify!([<$field_name Information>]), <Self as [<$name Value>]>::CLASS_ID as u8, value.class() as u8)),
125                        }
126                    }
127                }
128
129                impl [<$name Value>] for [<File $field_name Information>] {
130                    const CLASS_ID: [<$name Class>] = [<$name Class>]::[<$field_name Information>];
131                }
132            )*
133        }
134    }
135}
136
137pub(crate) use file_info_classes;