macro_rules! parse_any {
($vis:vis enum $enum:ident {
$(
$variant:ident($ty:ty)
),*
$(,)?
}) => {
$vis enum $enum<const WRITE: bool> {
$(
$variant($ty)
),*
}
impl<const WRITE: bool> ::syn::parse::Parse for $enum<WRITE> {
fn parse(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result<Self> {
use $crate::binrw::parser::macros::RwMarker;
$(if (<$ty as RwMarker>::READ == !WRITE || <$ty as RwMarker>::WRITE == WRITE) && <<$ty as $crate::meta_types::KeywordToken>::Token as ::syn::token::Token>::peek(input.cursor()) {
input.parse().map(Self::$variant)
} else)* {
let mut error = String::from("expected one of: ");
$(
if <$ty as RwMarker>::READ == !WRITE || <$ty as RwMarker>::WRITE == WRITE {
error.push_str(<$ty as $crate::meta_types::KeywordToken>::display());
error.push_str(", ");
}
)*
error.truncate(error.len() - 2);
Err(input.error(error))
}
}
}
};
}
pub(super) use parse_any;
macro_rules! attr_struct {
(
#[from($attr_ty:ident)]
$(#[$meta:meta])*
$vis:vis struct $ident:ident {
$(
$(#[doc = $field_doc:literal])*
$(#[cfg($($cfg_ident:tt)*)])?
$(#[from($($field_rw:ident : $field_attr_id:ident),+)])?
$field_vis:vis $field:ident : $field_ty:ty
),+ $(,)?
}
) => {
$(#[$meta])*
$vis struct $ident {
$(
$(#[cfg($($cfg_ident)*)])?
$(#[doc = $field_doc])*
$field_vis $field: $field_ty,
)+
#[cfg(feature = "verbose-backtrace")]
pub(crate) keyword_spans: Vec<proc_macro2::Span>,
}
impl<const WRITE: bool> $crate::binrw::parser::FromAttrs<$attr_ty<WRITE>> for $ident {
fn try_set_attr(&mut self, attr: $attr_ty<WRITE>) -> ::syn::Result<()> {
#[cfg(feature = "verbose-backtrace")]
use crate::meta_types::KeywordToken;
match attr {
$($(
$($attr_ty::$field_attr_id(value) => {
#[cfg(feature = "verbose-backtrace")]
self.keyword_spans.push(value.keyword_span());
value.into_inner().try_set(&mut self.$field)
},)+
)?)+
}
}
}
$crate::binrw::parser::macros::parse_any! {
$vis enum $attr_ty {
$($(
$($field_attr_id($crate::binrw::parser::macros::$field_rw<$crate::binrw::parser::attrs::$field_attr_id>),)+
)?)+
}
}
}
}
pub(super) use attr_struct;
pub(super) trait RwMarker {
const READ: bool;
const WRITE: bool;
}
macro_rules! rw_marker {
($ident:ident, $read:literal, $write:literal) => {
pub(crate) struct $ident<T>(T);
impl<T> $ident<T> {
pub(super) fn into_inner(self) -> T {
self.0
}
}
impl<T> RwMarker for $ident<T> {
const READ: bool = $read;
const WRITE: bool = $write;
}
impl<T: crate::meta_types::KeywordToken> crate::meta_types::KeywordToken for $ident<T> {
type Token = T::Token;
fn keyword_span(&self) -> proc_macro2::Span {
T::keyword_span(&self.0)
}
}
impl<T: syn::parse::Parse> syn::parse::Parse for $ident<T> {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
T::parse(input).map(Self)
}
}
};
}
rw_marker!(RO, true, false);
rw_marker!(WO, false, true);
rw_marker!(RW, true, true);