1use binrw::{
4 meta::{ReadEndian, WriteEndian},
5 prelude::*,
6};
7
8pub 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 type Class;
23
24 fn class(&self) -> Self::Class;
26}
27
28macro_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 #[doc = concat!("[`", stringify!($name), "`][crate::", stringify!($name), "].")]
43 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 #[doc = concat!("[`", stringify!($name), "`][crate::", stringify!($name), "]")]
60 #[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 #[doc = concat!("- [`", stringify!([<$name Class>]), "`][crate::", stringify!([<$name Class>]), "] - class IDs")]
75 #[doc = concat!("- [`", stringify!([<$name Value>]), "`][crate::", stringify!([<$name Value>]), "] - value trait")]
76 #[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;