smb_fscc/
info_classes.rs

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