use crate::{
datatype::{DataType, ObjectType, TupleType},
ExportError, ImplLocation,
};
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum EnumType {
Untagged {
variants: Vec<EnumVariant>,
generics: Vec<&'static str>,
},
Tagged {
variants: Vec<(&'static str, EnumVariant)>,
generics: Vec<&'static str>,
repr: EnumRepr,
},
}
impl From<EnumType> for DataType {
fn from(t: EnumType) -> Self {
Self::Enum(t)
}
}
impl EnumType {
pub(crate) fn generics(&self) -> &Vec<&'static str> {
match self {
Self::Untagged { generics, .. } => generics,
Self::Tagged { generics, .. } => generics,
}
}
pub(crate) fn variants_len(&self) -> usize {
match self {
Self::Untagged { variants, .. } => variants.len(),
Self::Tagged { variants, .. } => variants.len(),
}
}
pub fn make_flattenable(&mut self, impl_location: ImplLocation) -> Result<(), ExportError> {
match self {
Self::Untagged { variants, .. } => {
variants.iter().try_for_each(|v| match v {
EnumVariant::Unit => Ok(()),
EnumVariant::Named(_) => Ok(()),
EnumVariant::Unnamed(_) => Err(ExportError::InvalidType(
impl_location,
"`EnumRepr::Untagged` with ` EnumVariant::Unnamed` is invalid!",
)),
})?;
}
Self::Tagged { variants, repr, .. } => {
variants.iter().try_for_each(|(_, v)| {
match repr {
EnumRepr::External => match v {
EnumVariant::Unit => Err(ExportError::InvalidType(
impl_location,
"`EnumRepr::External` with ` EnumVariant::Unit` is invalid!",
)),
EnumVariant::Unnamed(v) if v.fields.len() == 1 => Ok(()),
EnumVariant::Unnamed(_) => Err(ExportError::InvalidType(
impl_location,
"`EnumRepr::External` with ` EnumVariant::Unnamed` containing more than a single field is invalid!",
)),
EnumVariant::Named(_) => Ok(()),
},
EnumRepr::Adjacent { .. } => Ok(()),
EnumRepr::Internal { .. } => match v {
EnumVariant::Unit => Ok(()),
EnumVariant::Named(_) => Ok(()),
EnumVariant::Unnamed(_) => Err(ExportError::InvalidType(
impl_location,
"`EnumRepr::Internal` with ` EnumVariant::Unnamed` is invalid!",
)),
},
}
})?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum EnumRepr {
External,
Internal {
tag: &'static str,
},
Adjacent {
tag: &'static str,
content: &'static str,
},
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum EnumVariant {
Unit,
Named(ObjectType),
Unnamed(TupleType),
}
impl EnumVariant {
pub fn data_type(&self) -> DataType {
match self {
Self::Unit => unreachable!("Unit enum variants have no type!"), Self::Unnamed(tuple_type) => tuple_type.clone().into(),
Self::Named(object_type) => object_type.clone().into(),
}
}
}