use binrw::{
meta::{ReadEndian, WriteEndian},
prelude::*,
};
pub trait FileInfoType:
Sized
+ for<'a> BinRead<Args<'static> = (Self::Class,)>
+ ReadEndian
+ for<'a> BinWrite<Args<'static> = ()>
+ WriteEndian
+ std::fmt::Debug
{
type Class;
fn class(&self) -> Self::Class;
}
macro_rules! file_info_classes {
(
$(#[doc = $docstring:literal])*
$svis:vis $name:ident {
$($vis:vis $field_name:ident = $cid:literal,)+
}
) => {
#[allow(unused_imports)]
use binrw::prelude::*;
pastey::paste! {
#[doc = concat!("[`", stringify!($name), "`][crate::", stringify!($name), "].")]
pub trait [<$name Value>] :
TryFrom<$name, Error = $crate::SmbFsccError>
+ Send + 'static
+ Into<$name>
+ for <'a> [<BinRead>]<Args<'a> = ()>
+ for <'b> [<BinWrite>]<Args<'b> = ()>
{
const CLASS_ID: [<$name Class>];
}
#[doc = concat!("[`", stringify!($name), "`][crate::", stringify!($name), "]")]
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[brw(repr(u8))]
$svis enum [<$name Class>] {
$(
$vis [<$field_name Information>] = $cid,
)*
}
$(#[doc = $docstring])*
#[doc = concat!("- [`", stringify!([<$name Class>]), "`][crate::", stringify!([<$name Class>]), "] - class IDs")]
#[doc = concat!("- [`", stringify!([<$name Value>]), "`][crate::", stringify!([<$name Value>]), "] - value trait")]
#[binrw::binrw]
#[derive(Debug, PartialEq, Eq)]
#[brw(little)]
#[br(import(c: [<$name Class>]))]
$svis enum $name {
$(
#[br(pre_assert(matches!(c, [<$name Class>]::[<$field_name Information>])))]
[<$field_name Information>]([<File $field_name Information>]),
)*
}
impl std::fmt::Display for [<$name Class>] {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$(
[<$name Class>]::[<$field_name Information>] => write!(f, stringify!([<$field_name Information>])),
)*
}
}
}
impl $crate::FileInfoType for $name {
type Class = [<$name Class>];
fn class(&self) -> Self::Class {
match self {
$(
$name::[<$field_name Information>](_) => [<$name Class>]::[<$field_name Information>],
)*
}
}
}
$(
impl From<[<File $field_name Information>]> for $name {
fn from(value: [<File $field_name Information>]) -> $name {
$name::[<$field_name Information>](value)
}
}
impl TryFrom<$name> for [<File $field_name Information>] {
type Error = $crate::SmbFsccError;
fn try_from(value: $name) -> Result<Self, Self::Error> {
pub use $crate::FileInfoType;
match value {
$name::[<$field_name Information>](v) => Ok(v),
_ => Err($crate::SmbFsccError::UnexpectedInformationType(stringify!([<$field_name Information>]), <Self as [<$name Value>]>::CLASS_ID as u8, value.class() as u8)),
}
}
}
impl [<$name Value>] for [<File $field_name Information>] {
const CLASS_ID: [<$name Class>] = [<$name Class>]::[<$field_name Information>];
}
)*
}
}
}
pub(crate) use file_info_classes;