use super::AttributeContainer;
use super::Field;
use super::FieldBuilder;
use super::Impl;
use super::ImplFor;
use super::Parent;
use super::Path;
use super::StreamBuilder;
use super::StringOrIdent;
use crate::Result;
use crate::parse::Generic;
use crate::parse::Generics;
use crate::parse::Visibility;
use crate::prelude::Delimiter;
use crate::prelude::Ident;
use crate::prelude::Span;
use crate::prelude::TokenStream;
pub struct GenEnum<'a, P: Parent> {
parent: &'a mut P,
name: Ident,
visibility: Visibility,
generics: Option<Generics>,
values: Vec<EnumValue>,
derives: Vec<Path>,
attributes: Vec<StreamBuilder>,
additional: Vec<StreamBuilder>,
}
impl<'a, P: Parent> GenEnum<'a, P> {
pub(crate) fn new(
parent: &'a mut P,
name: impl Into<String>,
) -> Self {
Self {
parent,
name: Ident::new(name.into().as_str(), Span::call_site()),
visibility: Visibility::Default,
generics: None,
values: Vec::new(),
derives: Vec::new(),
attributes: Vec::new(),
additional: Vec::new(),
}
}
pub const fn make_pub(&mut self) -> &mut Self {
self.visibility = Visibility::Pub;
self
}
pub fn with_derive(
&mut self,
derive: impl Into<Path>,
) -> &mut Self {
AttributeContainer::with_derive(self, derive)
}
pub fn with_derives<T: Into<Path>>(
&mut self,
derives: impl IntoIterator<Item = T>,
) -> &mut Self {
AttributeContainer::with_derives(self, derives)
}
pub fn with_attribute(
&mut self,
name: impl AsRef<str>,
value: impl FnOnce(&mut StreamBuilder) -> Result,
) -> Result<&mut Self> {
AttributeContainer::with_attribute(self, name, value)
}
pub fn with_parsed_attribute(
&mut self,
attribute: impl AsRef<str>,
) -> Result<&mut Self> {
AttributeContainer::with_parsed_attribute(self, attribute)
}
pub fn with_attribute_stream(
&mut self,
attribute: impl Into<TokenStream>,
) -> &mut Self {
AttributeContainer::with_attribute_stream(self, attribute)
}
pub fn inherit_generics(&mut self) -> &mut Self {
self.generics = self.parent.generics().cloned();
self
}
pub fn with_generics(
&mut self,
generics: impl IntoIterator<Item = Generic>,
) -> &mut Self {
self.generics
.get_or_insert_with(|| Generics(Vec::new()))
.extend(generics);
self
}
pub fn with_generic(
&mut self,
generic: Generic,
) -> &mut Self {
self.generics
.get_or_insert_with(|| Generics(Vec::new()))
.push(generic);
self
}
pub fn add_value(
&mut self,
name: impl Into<String>,
) -> &mut EnumValue {
self.values.push(EnumValue::new(name));
self.values.last_mut().unwrap()
}
pub fn impl_for(
&mut self,
name: impl Into<StringOrIdent>,
) -> ImplFor<'_, Self> {
ImplFor::new(self, name.into(), None)
}
pub fn r#impl(&mut self) -> Impl<'_, Self> {
Impl::with_parent_name(self)
}
pub fn generate_impl(&mut self) -> Impl<'_, Self> {
Impl::with_parent_name(self)
}
}
impl<P: Parent> AttributeContainer for GenEnum<'_, P> {
fn derives(&mut self) -> &mut Vec<Path> {
&mut self.derives
}
fn attributes(&mut self) -> &mut Vec<StreamBuilder> {
&mut self.attributes
}
}
impl<P: Parent> Parent for GenEnum<'_, P> {
fn append(
&mut self,
builder: StreamBuilder,
) {
self.additional.push(builder);
}
fn name(&self) -> &Ident {
&self.name
}
fn generics(&self) -> Option<&Generics> {
self.generics.as_ref()
}
fn generic_constraints(&self) -> Option<&crate::parse::GenericConstraints> {
None
}
}
impl<P: Parent> Drop for GenEnum<'_, P> {
fn drop(&mut self) {
let mut builder = StreamBuilder::new();
self.build_derives(&mut builder)
.build_attributes(&mut builder);
if self.visibility == Visibility::Pub {
builder.ident_str("pub");
}
builder
.ident_str("enum")
.ident(self.name.clone())
.append(
self.generics()
.map(Generics::impl_generics)
.unwrap_or_default(),
)
.group(Delimiter::Brace, |b| {
for value in &mut self.values {
build_value(b, value)?;
}
Ok(())
})
.expect("Could not build enum");
for additional in std::mem::take(&mut self.additional) {
builder.append(additional);
}
self.parent.append(builder);
}
}
fn build_value(
builder: &mut StreamBuilder,
value: &mut EnumValue,
) -> Result {
value.build_attributes(builder);
builder.ident(value.name.clone());
match value.value_type {
| ValueType::Named => {
builder.group(Delimiter::Brace, |b| {
for field in &mut value.fields {
field.build_attributes(b);
if field.vis == Visibility::Pub {
b.ident_str("pub");
}
b.ident_str(&field.name)
.punct(':')
.push_parsed(&field.ty)?
.punct(',');
}
Ok(())
})?
},
| ValueType::Unnamed => {
builder.group(Delimiter::Parenthesis, |b| {
for field in &mut value.fields {
field.build_attributes(b);
if field.vis == Visibility::Pub {
b.ident_str("pub");
}
b.push_parsed(&field.ty)?.punct(',');
}
Ok(())
})?
},
| ValueType::Zst => builder,
};
builder.punct(',');
Ok(())
}
pub struct EnumValue {
name: Ident,
fields: Vec<Field>,
value_type: ValueType,
attributes: Vec<StreamBuilder>,
}
impl EnumValue {
fn new(name: impl Into<String>) -> Self {
Self {
name: Ident::new(name.into().as_str(), Span::call_site()),
fields: Vec::new(),
value_type: ValueType::Named,
attributes: Vec::new(),
}
}
pub const fn make_zst(&mut self) -> &mut Self {
self.value_type = ValueType::Zst;
self
}
pub const fn make_tuple(&mut self) -> &mut Self {
self.value_type = ValueType::Unnamed;
self
}
pub fn with_attribute(
&mut self,
name: impl AsRef<str>,
value: impl FnOnce(&mut StreamBuilder) -> Result,
) -> Result<&mut Self> {
AttributeContainer::with_attribute(self, name, value)
}
pub fn with_parsed_attribute(
&mut self,
attribute: impl AsRef<str>,
) -> Result<&mut Self> {
AttributeContainer::with_parsed_attribute(self, attribute)
}
pub fn with_attribute_stream(
&mut self,
attribute: impl Into<TokenStream>,
) -> &mut Self {
AttributeContainer::with_attribute_stream(self, attribute)
}
pub fn add_field(
&mut self,
name: impl Into<String>,
ty: impl Into<String>,
) -> FieldBuilder<'_, Self> {
let mut fields = FieldBuilder::from(&mut self.fields);
fields.add_field(name, ty);
fields
}
}
impl AttributeContainer for EnumValue {
fn derives(&mut self) -> &mut Vec<Path> {
unreachable!("enum variants cannot have derives")
}
fn attributes(&mut self) -> &mut Vec<StreamBuilder> {
&mut self.attributes
}
}
enum ValueType {
Named,
Unnamed,
Zst,
}