xso-proc: refactor enum handling

This will allow other kinds of enumerations in the future more
easily.
This commit is contained in:
Jonas Schäfer 2024-08-05 15:45:40 +02:00 committed by Link Mauve
commit b36d1d0d4c

View file

@ -140,8 +140,7 @@ impl NameVariant {
} }
} }
/// Definition of an enum and how to parse it. struct NameSwitchedEnum {
pub(crate) struct EnumDef {
/// The XML namespace of the element to map the enum to. /// The XML namespace of the element to map the enum to.
namespace: NamespaceRef, namespace: NamespaceRef,
@ -150,24 +149,10 @@ pub(crate) struct EnumDef {
/// Flag indicating whether the enum is exhaustive. /// Flag indicating whether the enum is exhaustive.
exhaustive: bool, exhaustive: bool,
/// Name of the target type.
target_ty_ident: Ident,
/// Name of the builder type.
builder_ty_ident: Ident,
/// Name of the iterator type.
item_iter_ty_ident: Ident,
/// Flag whether debug mode is enabled.
debug: bool,
} }
impl EnumDef { impl NameSwitchedEnum {
/// Create a new enum from its name, meta, and variants. fn new<'x, I: IntoIterator<Item = &'x Variant>>(
pub(crate) fn new<'x, I: IntoIterator<Item = &'x Variant>>(
ident: &Ident,
meta: XmlCompoundMeta, meta: XmlCompoundMeta,
variant_iter: I, variant_iter: I,
) -> Result<Self> { ) -> Result<Self> {
@ -184,6 +169,13 @@ impl EnumDef {
transparent, transparent,
} = meta; } = meta;
// These must've been cleared by the caller. Because these being set
// is a programming error (in xso-proc) and not a usage error, we
// assert here instead of using reject_key!.
assert!(builder.is_none());
assert!(iterator.is_none());
assert!(!debug.is_set());
reject_key!(name not on "enums" only on "their variants"); reject_key!(name not on "enums" only on "their variants");
reject_key!(transparent flag not on "enums" only on "structs"); reject_key!(transparent flag not on "enums" only on "structs");
@ -208,44 +200,24 @@ impl EnumDef {
variants.push(variant); variants.push(variant);
} }
let builder_ty_ident = match builder {
Some(v) => v,
None => quote::format_ident!("{}FromXmlBuilder", ident.to_string()),
};
let item_iter_ty_ident = match iterator {
Some(v) => v,
None => quote::format_ident!("{}AsXmlIterator", ident.to_string()),
};
Ok(Self { Ok(Self {
namespace, namespace,
variants, variants,
exhaustive: exhaustive.is_set(), exhaustive: exhaustive.is_set(),
target_ty_ident: ident.clone(),
builder_ty_ident,
item_iter_ty_ident,
debug: debug.is_set(),
}) })
} }
}
impl ItemDef for EnumDef { fn make_from_events_statemachine(
fn make_from_events_builder(
&self, &self,
vis: &Visibility, target_ty_ident: &Ident,
name_ident: &Ident, state_ty_ident: &Ident,
attrs_ident: &Ident, ) -> Result<FromEventsStateMachine> {
) -> Result<FromXmlParts> {
let xml_namespace = &self.namespace; let xml_namespace = &self.namespace;
let target_ty_ident = &self.target_ty_ident;
let builder_ty_ident = &self.builder_ty_ident;
let state_ty_ident = quote::format_ident!("{}State", builder_ty_ident);
let mut statemachine = FromEventsStateMachine::new(); let mut statemachine = FromEventsStateMachine::new();
for variant in self.variants.iter() { for variant in self.variants.iter() {
statemachine statemachine
.merge(variant.make_from_events_statemachine(target_ty_ident, &state_ty_ident)?); .merge(variant.make_from_events_statemachine(target_ty_ident, state_ty_ident)?);
} }
statemachine.set_pre_init(quote! { statemachine.set_pre_init(quote! {
@ -266,16 +238,100 @@ impl ItemDef for EnumDef {
}) })
} }
let defs = statemachine.render( Ok(statemachine)
vis, }
fn make_as_item_iter_statemachine(
&self,
target_ty_ident: &Ident,
state_ty_ident: &Ident,
item_iter_ty_lifetime: &Lifetime,
) -> Result<AsItemsStateMachine> {
let mut statemachine = AsItemsStateMachine::new();
for variant in self.variants.iter() {
statemachine.merge(variant.make_as_item_iter_statemachine(
&self.namespace,
target_ty_ident,
state_ty_ident,
item_iter_ty_lifetime,
)?);
}
Ok(statemachine)
}
}
/// Definition of an enum and how to parse it.
pub(crate) struct EnumDef {
/// Implementation of the enum itself
inner: NameSwitchedEnum,
/// Name of the target type.
target_ty_ident: Ident,
/// Name of the builder type.
builder_ty_ident: Ident,
/// Name of the iterator type.
item_iter_ty_ident: Ident,
/// Flag whether debug mode is enabled.
debug: bool,
}
impl EnumDef {
/// Create a new enum from its name, meta, and variants.
pub(crate) fn new<'x, I: IntoIterator<Item = &'x Variant>>(
ident: &Ident,
mut meta: XmlCompoundMeta,
variant_iter: I,
) -> Result<Self> {
let builder_ty_ident = match meta.builder.take() {
Some(v) => v,
None => quote::format_ident!("{}FromXmlBuilder", ident.to_string()),
};
let item_iter_ty_ident = match meta.iterator.take() {
Some(v) => v,
None => quote::format_ident!("{}AsXmlIterator", ident.to_string()),
};
let debug = meta.debug.take().is_set();
Ok(Self {
inner: NameSwitchedEnum::new(meta, variant_iter)?,
target_ty_ident: ident.clone(),
builder_ty_ident, builder_ty_ident,
&state_ty_ident, item_iter_ty_ident,
&TypePath { debug,
qself: None, })
path: target_ty_ident.clone().into(), }
} }
.into(),
)?; impl ItemDef for EnumDef {
fn make_from_events_builder(
&self,
vis: &Visibility,
name_ident: &Ident,
attrs_ident: &Ident,
) -> Result<FromXmlParts> {
let target_ty_ident = &self.target_ty_ident;
let builder_ty_ident = &self.builder_ty_ident;
let state_ty_ident = quote::format_ident!("{}State", builder_ty_ident);
let defs = self
.inner
.make_from_events_statemachine(target_ty_ident, &state_ty_ident)?
.render(
vis,
builder_ty_ident,
&state_ty_ident,
&TypePath {
qself: None,
path: target_ty_ident.clone().into(),
}
.into(),
)?;
Ok(FromXmlParts { Ok(FromXmlParts {
defs, defs,
@ -318,26 +374,23 @@ impl ItemDef for EnumDef {
}); });
let state_ty_ident = quote::format_ident!("{}State", item_iter_ty_ident); let state_ty_ident = quote::format_ident!("{}State", item_iter_ty_ident);
let mut statemachine = AsItemsStateMachine::new(); let defs = self
for variant in self.variants.iter() { .inner
statemachine.merge(variant.make_as_item_iter_statemachine( .make_as_item_iter_statemachine(
&self.namespace,
target_ty_ident, target_ty_ident,
&state_ty_ident, &state_ty_ident,
&item_iter_ty_lifetime, &item_iter_ty_lifetime,
)?); )?
} .render(
vis,
let defs = statemachine.render( &ref_ty(
vis, ty_from_ident(target_ty_ident.clone()).into(),
&ref_ty( item_iter_ty_lifetime.clone(),
ty_from_ident(target_ty_ident.clone()).into(), ),
item_iter_ty_lifetime.clone(), &state_ty_ident,
), &item_iter_ty_lifetime,
&state_ty_ident, &item_iter_ty,
&item_iter_ty_lifetime, )?;
&item_iter_ty,
)?;
Ok(AsXmlParts { Ok(AsXmlParts {
defs, defs,