mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
xso-proc: refactor struct processing
If we are going to support structs with fields, it would be good to have that struct-related code organised a little and less splashed over the main lib.rs file.
This commit is contained in:
parent
2efef5ceeb
commit
bf7816d321
2 changed files with 243 additions and 143 deletions
|
@ -21,30 +21,23 @@ return to `xso` for more information**. The documentation of
|
||||||
// syn mostly works with proc_macro2, while the proc macros themselves use
|
// syn mostly works with proc_macro2, while the proc macros themselves use
|
||||||
// proc_macro.
|
// proc_macro.
|
||||||
use proc_macro::TokenStream as RawTokenStream;
|
use proc_macro::TokenStream as RawTokenStream;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::*;
|
use syn::*;
|
||||||
|
|
||||||
mod meta;
|
mod meta;
|
||||||
|
mod structs;
|
||||||
|
|
||||||
/// Convert an [`syn::Item`] into the parts relevant for us.
|
/// Convert an [`syn::Item`] into the parts relevant for us.
|
||||||
///
|
///
|
||||||
/// If the item is of an unsupported variant, an appropriate error is
|
/// If the item is of an unsupported variant, an appropriate error is
|
||||||
/// returned.
|
/// returned.
|
||||||
fn parse_struct(item: Item) -> Result<(Visibility, meta::XmlCompoundMeta, Ident)> {
|
fn parse_struct(item: Item) -> Result<(Visibility, Ident, structs::StructDef)> {
|
||||||
match item {
|
match item {
|
||||||
Item::Struct(item) => {
|
Item::Struct(item) => {
|
||||||
match item.fields {
|
|
||||||
Fields::Unit => (),
|
|
||||||
other => {
|
|
||||||
return Err(Error::new_spanned(
|
|
||||||
other,
|
|
||||||
"cannot derive on non-unit struct (yet!)",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let meta = meta::XmlCompoundMeta::parse_from_attributes(&item.attrs)?;
|
let meta = meta::XmlCompoundMeta::parse_from_attributes(&item.attrs)?;
|
||||||
Ok((item.vis, meta, item.ident))
|
let def = structs::StructDef::new(&item.ident, meta, &item.fields)?;
|
||||||
|
Ok((item.vis, item.ident, def))
|
||||||
}
|
}
|
||||||
other => Err(Error::new_spanned(other, "cannot derive on this item")),
|
other => Err(Error::new_spanned(other, "cannot derive on this item")),
|
||||||
}
|
}
|
||||||
|
@ -53,90 +46,29 @@ fn parse_struct(item: Item) -> Result<(Visibility, meta::XmlCompoundMeta, Ident)
|
||||||
/// Generate a `xso::FromXml` implementation for the given item, or fail with
|
/// Generate a `xso::FromXml` implementation for the given item, or fail with
|
||||||
/// a proper compiler error.
|
/// a proper compiler error.
|
||||||
fn from_xml_impl(input: Item) -> Result<TokenStream> {
|
fn from_xml_impl(input: Item) -> Result<TokenStream> {
|
||||||
let (
|
let (vis, ident, def) = parse_struct(input)?;
|
||||||
vis,
|
|
||||||
meta::XmlCompoundMeta {
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
ident,
|
|
||||||
) = parse_struct(input)?;
|
|
||||||
|
|
||||||
// we rebind to a different name here because otherwise some expressions
|
let name_ident = Ident::new("name", Span::call_site());
|
||||||
// inside `quote! {}` below get a bit tricky to read (such as
|
let attrs_ident = Ident::new("attrs", Span::call_site());
|
||||||
// `name.1 == #name`).
|
|
||||||
let Some(xml_namespace) = namespace else {
|
|
||||||
return Err(Error::new(span, "`namespace` key is required"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(xml_name) = name else {
|
let structs::FromXmlParts {
|
||||||
return Err(Error::new(span, "`name` key is required"));
|
defs,
|
||||||
};
|
from_events_body,
|
||||||
|
builder_ty_ident,
|
||||||
let from_events_builder_ty_name = quote::format_ident!("{}FromEvents", ident);
|
} = def.make_from_events_builder(&vis, &name_ident, &attrs_ident)?;
|
||||||
let state_ty_name = quote::format_ident!("{}FromEventsState", ident);
|
|
||||||
|
|
||||||
let unknown_attr_err = format!(
|
|
||||||
"Unknown attribute in {} element.",
|
|
||||||
xml_name.repr_to_string()
|
|
||||||
);
|
|
||||||
let unknown_child_err = format!("Unknown child in {} element.", xml_name.repr_to_string());
|
|
||||||
let docstr = format!("Build a [`{}`] from XML events", ident);
|
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
|
#[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
|
||||||
let mut result = quote! {
|
let mut result = quote! {
|
||||||
enum #state_ty_name {
|
#defs
|
||||||
Default,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = #docstr]
|
|
||||||
#vis struct #from_events_builder_ty_name(::core::option::Option<#state_ty_name>);
|
|
||||||
|
|
||||||
impl ::xso::FromEventsBuilder for #from_events_builder_ty_name {
|
|
||||||
type Output = #ident;
|
|
||||||
|
|
||||||
fn feed(
|
|
||||||
&mut self,
|
|
||||||
ev: ::xso::exports::rxml::Event
|
|
||||||
) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
|
|
||||||
match self.0 {
|
|
||||||
::core::option::Option::None => panic!("feed() called after it returned a non-None value"),
|
|
||||||
::core::option::Option::Some(#state_ty_name::Default) => match ev {
|
|
||||||
::xso::exports::rxml::Event::StartElement(..) => {
|
|
||||||
::core::result::Result::Err(::xso::error::Error::Other(#unknown_child_err))
|
|
||||||
}
|
|
||||||
::xso::exports::rxml::Event::EndElement(..) => {
|
|
||||||
self.0 = ::core::option::Option::None;
|
|
||||||
::core::result::Result::Ok(::core::option::Option::Some(#ident))
|
|
||||||
}
|
|
||||||
::xso::exports::rxml::Event::Text(..) => {
|
|
||||||
::core::result::Result::Err(::xso::error::Error::Other("Unexpected text content".into()))
|
|
||||||
}
|
|
||||||
// we ignore these: a correct parser only generates
|
|
||||||
// them at document start, and there we want to indeed
|
|
||||||
// not worry about them being in front of the first
|
|
||||||
// element.
|
|
||||||
::xso::exports::rxml::Event::XmlDeclaration(_, ::xso::exports::rxml::XmlVersion::V1_0) => ::core::result::Result::Ok(::core::option::Option::None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::xso::FromXml for #ident {
|
impl ::xso::FromXml for #ident {
|
||||||
type Builder = #from_events_builder_ty_name;
|
type Builder = #builder_ty_ident;
|
||||||
|
|
||||||
fn from_events(
|
fn from_events(
|
||||||
name: ::xso::exports::rxml::QName,
|
name: ::xso::exports::rxml::QName,
|
||||||
attrs: ::xso::exports::rxml::AttrMap,
|
attrs: ::xso::exports::rxml::AttrMap,
|
||||||
) -> ::core::result::Result<Self::Builder, ::xso::error::FromEventsError> {
|
) -> ::core::result::Result<Self::Builder, ::xso::error::FromEventsError> {
|
||||||
if name.0 != #xml_namespace || name.1 != #xml_name {
|
#from_events_body
|
||||||
return ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch { name, attrs });
|
|
||||||
}
|
|
||||||
if attrs.len() > 0 {
|
|
||||||
return ::core::result::Result::Err(::xso::error::Error::Other(#unknown_attr_err).into());
|
|
||||||
}
|
|
||||||
::core::result::Result::Ok(#from_events_builder_ty_name(::core::option::Option::Some(#state_ty_name::Default)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -172,73 +104,23 @@ pub fn from_xml(input: RawTokenStream) -> RawTokenStream {
|
||||||
/// Generate a `xso::IntoXml` implementation for the given item, or fail with
|
/// Generate a `xso::IntoXml` implementation for the given item, or fail with
|
||||||
/// a proper compiler error.
|
/// a proper compiler error.
|
||||||
fn into_xml_impl(input: Item) -> Result<TokenStream> {
|
fn into_xml_impl(input: Item) -> Result<TokenStream> {
|
||||||
let (
|
let (vis, ident, def) = parse_struct(input)?;
|
||||||
vis,
|
|
||||||
meta::XmlCompoundMeta {
|
|
||||||
namespace,
|
|
||||||
name,
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
ident,
|
|
||||||
) = parse_struct(input)?;
|
|
||||||
|
|
||||||
// we rebind to a different name here to stay consistent with
|
let structs::IntoXmlParts {
|
||||||
// `from_xml_impl`.
|
defs,
|
||||||
let Some(xml_namespace) = namespace else {
|
into_event_iter_body,
|
||||||
return Err(Error::new(span, "`namespace` key is required"));
|
event_iter_ty_ident,
|
||||||
};
|
} = def.make_into_event_iter(&vis)?;
|
||||||
|
|
||||||
let Some(xml_name) = name else {
|
|
||||||
return Err(Error::new(span, "`name` key is required"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let into_events_iter_ty_name = quote::format_ident!("{}IntoEvents", ident);
|
|
||||||
let state_ty_name = quote::format_ident!("{}IntoEventsState", ident);
|
|
||||||
|
|
||||||
let docstr = format!("Decompose a [`{}`] into XML events", ident);
|
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
|
#[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
|
||||||
let mut result = quote! {
|
let mut result = quote! {
|
||||||
enum #state_ty_name {
|
#defs
|
||||||
Header,
|
|
||||||
Footer,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc = #docstr]
|
|
||||||
#vis struct #into_events_iter_ty_name(::core::option::Option<#state_ty_name>);
|
|
||||||
|
|
||||||
impl ::std::iter::Iterator for #into_events_iter_ty_name {
|
|
||||||
type Item = ::core::result::Result<::xso::exports::rxml::Event, ::xso::error::Error>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> ::core::option::Option<Self::Item> {
|
|
||||||
match self.0 {
|
|
||||||
::core::option::Option::Some(#state_ty_name::Header) => {
|
|
||||||
self.0 = ::core::option::Option::Some(#state_ty_name::Footer);
|
|
||||||
::core::option::Option::Some(::core::result::Result::Ok(::xso::exports::rxml::Event::StartElement(
|
|
||||||
::xso::exports::rxml::parser::EventMetrics::zero(),
|
|
||||||
(
|
|
||||||
::xso::exports::rxml::Namespace::from_str(#xml_namespace),
|
|
||||||
#xml_name.to_owned(),
|
|
||||||
),
|
|
||||||
::xso::exports::rxml::AttrMap::new(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
::core::option::Option::Some(#state_ty_name::Footer) => {
|
|
||||||
self.0 = ::core::option::Option::None;
|
|
||||||
::core::option::Option::Some(::core::result::Result::Ok(::xso::exports::rxml::Event::EndElement(
|
|
||||||
::xso::exports::rxml::parser::EventMetrics::zero(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
::core::option::Option::None => ::core::option::Option::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::xso::IntoXml for #ident {
|
impl ::xso::IntoXml for #ident {
|
||||||
type EventIter = #into_events_iter_ty_name;
|
type EventIter = #event_iter_ty_ident;
|
||||||
|
|
||||||
fn into_event_iter(self) -> ::core::result::Result<Self::EventIter, ::xso::error::Error> {
|
fn into_event_iter(self) -> ::core::result::Result<Self::EventIter, ::xso::error::Error> {
|
||||||
::core::result::Result::Ok(#into_events_iter_ty_name(::core::option::Option::Some(#state_ty_name::Header)))
|
#into_event_iter_body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
218
xso-proc/src/structs.rs
Normal file
218
xso-proc/src/structs.rs
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
// Copyright (c) 2024 Jonas Schäfer <jonas@zombofant.net>
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
//! Handling of structs
|
||||||
|
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::*;
|
||||||
|
|
||||||
|
use crate::meta::{NameRef, NamespaceRef, XmlCompoundMeta};
|
||||||
|
|
||||||
|
/// Parts necessary to construct a `::xso::FromXml` implementation.
|
||||||
|
pub(crate) struct FromXmlParts {
|
||||||
|
/// Additional items necessary for the implementation.
|
||||||
|
pub(crate) defs: TokenStream,
|
||||||
|
|
||||||
|
/// The body of the `::xso::FromXml::from_xml` function.
|
||||||
|
pub(crate) from_events_body: TokenStream,
|
||||||
|
|
||||||
|
/// The name of the type which is the `::xso::FromXml::Builder`.
|
||||||
|
pub(crate) builder_ty_ident: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parts necessary to construct a `::xso::IntoXml` implementation.
|
||||||
|
pub(crate) struct IntoXmlParts {
|
||||||
|
/// Additional items necessary for the implementation.
|
||||||
|
pub(crate) defs: TokenStream,
|
||||||
|
|
||||||
|
/// The body of the `::xso::IntoXml::into_event_iter` function.
|
||||||
|
pub(crate) into_event_iter_body: TokenStream,
|
||||||
|
|
||||||
|
/// The name of the type which is the `::xso::IntoXml::EventIter`.
|
||||||
|
pub(crate) event_iter_ty_ident: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Definition of a struct and how to parse it.
|
||||||
|
pub(crate) struct StructDef {
|
||||||
|
/// The XML namespace of the element to map the struct to.
|
||||||
|
namespace: NamespaceRef,
|
||||||
|
|
||||||
|
/// The XML name of the element to map the struct to.
|
||||||
|
name: NameRef,
|
||||||
|
|
||||||
|
/// Name of the target type.
|
||||||
|
target_ty_ident: Ident,
|
||||||
|
|
||||||
|
/// Name of the builder type.
|
||||||
|
builder_ty_ident: Ident,
|
||||||
|
|
||||||
|
/// Name of the iterator type.
|
||||||
|
event_iter_ty_ident: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructDef {
|
||||||
|
/// Create a new struct from its name, meta, and fields.
|
||||||
|
pub(crate) fn new(ident: &Ident, meta: XmlCompoundMeta, fields: &Fields) -> Result<Self> {
|
||||||
|
let Some(namespace) = meta.namespace else {
|
||||||
|
return Err(Error::new(meta.span, "`namespace` is required on structs"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(name) = meta.name else {
|
||||||
|
return Err(Error::new(meta.span, "`name` is required on structs"));
|
||||||
|
};
|
||||||
|
|
||||||
|
match fields {
|
||||||
|
Fields::Unit => (),
|
||||||
|
other => {
|
||||||
|
return Err(Error::new_spanned(
|
||||||
|
other,
|
||||||
|
"cannot derive on non-unit struct (yet!)",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
namespace,
|
||||||
|
name,
|
||||||
|
target_ty_ident: ident.clone(),
|
||||||
|
builder_ty_ident: quote::format_ident!("{}FromXmlBuilder", ident),
|
||||||
|
event_iter_ty_ident: quote::format_ident!("{}IntoXmlIterator", ident),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn make_from_events_builder(
|
||||||
|
&self,
|
||||||
|
vis: &Visibility,
|
||||||
|
name_ident: &Ident,
|
||||||
|
attrs_ident: &Ident,
|
||||||
|
) -> Result<FromXmlParts> {
|
||||||
|
let xml_namespace = &self.namespace;
|
||||||
|
let xml_name = &self.name;
|
||||||
|
|
||||||
|
let target_ty_ident = &self.target_ty_ident;
|
||||||
|
let builder_ty_ident = &self.builder_ty_ident;
|
||||||
|
let state_ty_name = quote::format_ident!("{}State", builder_ty_ident);
|
||||||
|
|
||||||
|
let unknown_attr_err = format!(
|
||||||
|
"Unknown attribute in {} element.",
|
||||||
|
xml_name.repr_to_string()
|
||||||
|
);
|
||||||
|
let unknown_child_err = format!("Unknown child in {} element.", xml_name.repr_to_string());
|
||||||
|
|
||||||
|
let docstr = format!("Build a [`{}`] from XML events", target_ty_ident);
|
||||||
|
|
||||||
|
Ok(FromXmlParts {
|
||||||
|
defs: quote! {
|
||||||
|
enum #state_ty_name {
|
||||||
|
Default,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = #docstr]
|
||||||
|
#vis struct #builder_ty_ident(::core::option::Option<#state_ty_name>);
|
||||||
|
|
||||||
|
impl ::xso::FromEventsBuilder for #builder_ty_ident {
|
||||||
|
type Output = #target_ty_ident;
|
||||||
|
|
||||||
|
fn feed(
|
||||||
|
&mut self,
|
||||||
|
ev: ::xso::exports::rxml::Event
|
||||||
|
) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
|
||||||
|
match self.0 {
|
||||||
|
::core::option::Option::None => panic!("feed() called after it returned a non-None value"),
|
||||||
|
::core::option::Option::Some(#state_ty_name::Default) => match ev {
|
||||||
|
::xso::exports::rxml::Event::StartElement(..) => {
|
||||||
|
::core::result::Result::Err(::xso::error::Error::Other(#unknown_child_err))
|
||||||
|
}
|
||||||
|
::xso::exports::rxml::Event::EndElement(..) => {
|
||||||
|
self.0 = ::core::option::Option::None;
|
||||||
|
::core::result::Result::Ok(::core::option::Option::Some(#target_ty_ident))
|
||||||
|
}
|
||||||
|
::xso::exports::rxml::Event::Text(..) => {
|
||||||
|
::core::result::Result::Err(::xso::error::Error::Other("Unexpected text content".into()))
|
||||||
|
}
|
||||||
|
// we ignore these: a correct parser only generates
|
||||||
|
// them at document start, and there we want to indeed
|
||||||
|
// not worry about them being in front of the first
|
||||||
|
// element.
|
||||||
|
::xso::exports::rxml::Event::XmlDeclaration(_, ::xso::exports::rxml::XmlVersion::V1_0) => ::core::result::Result::Ok(::core::option::Option::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
from_events_body: quote! {
|
||||||
|
if #name_ident.0 != #xml_namespace || #name_ident.1 != #xml_name {
|
||||||
|
return ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch {
|
||||||
|
name: #name_ident,
|
||||||
|
attrs: #attrs_ident,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if attrs.len() > 0 {
|
||||||
|
return ::core::result::Result::Err(::xso::error::Error::Other(
|
||||||
|
#unknown_attr_err,
|
||||||
|
).into());
|
||||||
|
}
|
||||||
|
::core::result::Result::Ok(#builder_ty_ident(::core::option::Option::Some(#state_ty_name::Default)))
|
||||||
|
},
|
||||||
|
builder_ty_ident: builder_ty_ident.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn make_into_event_iter(&self, vis: &Visibility) -> Result<IntoXmlParts> {
|
||||||
|
let xml_namespace = &self.namespace;
|
||||||
|
let xml_name = &self.name;
|
||||||
|
|
||||||
|
let target_ty_ident = &self.target_ty_ident;
|
||||||
|
let event_iter_ty_ident = &self.event_iter_ty_ident;
|
||||||
|
let state_ty_name = quote::format_ident!("{}State", event_iter_ty_ident);
|
||||||
|
|
||||||
|
let docstr = format!("Decompose a [`{}`] into XML events", target_ty_ident);
|
||||||
|
|
||||||
|
Ok(IntoXmlParts {
|
||||||
|
defs: quote! {
|
||||||
|
enum #state_ty_name {
|
||||||
|
Header,
|
||||||
|
Footer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = #docstr]
|
||||||
|
#vis struct #event_iter_ty_ident(::core::option::Option<#state_ty_name>);
|
||||||
|
|
||||||
|
impl ::std::iter::Iterator for #event_iter_ty_ident {
|
||||||
|
type Item = ::core::result::Result<::xso::exports::rxml::Event, ::xso::error::Error>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> ::core::option::Option<Self::Item> {
|
||||||
|
match self.0 {
|
||||||
|
::core::option::Option::Some(#state_ty_name::Header) => {
|
||||||
|
self.0 = ::core::option::Option::Some(#state_ty_name::Footer);
|
||||||
|
::core::option::Option::Some(::core::result::Result::Ok(::xso::exports::rxml::Event::StartElement(
|
||||||
|
::xso::exports::rxml::parser::EventMetrics::zero(),
|
||||||
|
(
|
||||||
|
::xso::exports::rxml::Namespace::from_str(#xml_namespace),
|
||||||
|
#xml_name.to_owned(),
|
||||||
|
),
|
||||||
|
::xso::exports::rxml::AttrMap::new(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
::core::option::Option::Some(#state_ty_name::Footer) => {
|
||||||
|
self.0 = ::core::option::Option::None;
|
||||||
|
::core::option::Option::Some(::core::result::Result::Ok(::xso::exports::rxml::Event::EndElement(
|
||||||
|
::xso::exports::rxml::parser::EventMetrics::zero(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
::core::option::Option::None => ::core::option::Option::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
into_event_iter_body: quote! {
|
||||||
|
::core::result::Result::Ok(#event_iter_ty_ident(::core::option::Option::Some(#state_ty_name::Header)))
|
||||||
|
},
|
||||||
|
event_iter_ty_ident: event_iter_ty_ident.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue