diff --git a/macros/src/type/enum.rs b/macros/src/type/enum.rs index baedb93..af6198e 100644 --- a/macros/src/type/enum.rs +++ b/macros/src/type/enum.rs @@ -181,10 +181,7 @@ pub fn parse_enum( let (enum_impl, can_flatten) = match repr { Tagged::Untagged => ( quote! { - #crate_ref::EnumType::Untagged { - generics: vec![#(#definition_generics),*], - variants: vec![#(#variant_types),*], - } + #crate_ref::internal::construct::untagged_enum(vec![#(#variant_types),*], vec![#(#definition_generics),*]) }, data.variants .iter() @@ -192,11 +189,11 @@ pub fn parse_enum( ), Tagged::Externally => ( quote! { - #crate_ref::EnumType::Tagged { - generics: vec![#(#definition_generics),*], - variants: vec![#((#variant_names.into(), #variant_types)),*], - repr: #crate_ref::EnumRepr::External, - } + #crate_ref::internal::construct::tagged_enum( + vec![#((#variant_names.into(), #variant_types)),*], + vec![#(#definition_generics),*], + #crate_ref::EnumRepr::External + ) }, data.variants.iter().any(|v| match &v.fields { Fields::Unnamed(f) if f.unnamed.len() == 1 => true, @@ -206,21 +203,21 @@ pub fn parse_enum( ), Tagged::Adjacently { tag, content } => ( quote! { - #crate_ref::EnumType::Tagged { - generics: vec![#(#definition_generics),*], - variants: vec![#((#variant_names.into(), #variant_types)),*], - repr: #crate_ref::EnumRepr::Adjacent { tag: #tag.into(), content: #content.into() }, - } + #crate_ref::internal::construct::tagged_enum( + vec![#((#variant_names.into(), #variant_types)),*], + vec![#(#definition_generics),*], + #crate_ref::EnumRepr::Adjacent { tag: #tag.into(), content: #content.into() } + ) }, true, ), Tagged::Internally { tag } => ( quote! { - #crate_ref::EnumType::Tagged { - generics: vec![#(#definition_generics),*], - variants: vec![#((#variant_names.into(), #variant_types)),*], - repr: #crate_ref::EnumRepr::Internal { tag: #tag.into() }, - } + #crate_ref::internal::construct::tagged_enum( + vec![#((#variant_names.into(), #variant_types)),*], + vec![#(#definition_generics),*], + #crate_ref::EnumRepr::Internal { tag: #tag.into() }, + ) }, data.variants .iter() diff --git a/src/datatype/enum.rs b/src/datatype/enum.rs index d440360..a0b7d52 100644 --- a/src/datatype/enum.rs +++ b/src/datatype/enum.rs @@ -5,6 +5,55 @@ use crate::{ ExportError, GenericType, ImplLocation, }; +#[derive(Debug, Clone, PartialEq)] +pub struct UntaggedEnum { + pub(crate) variants: Vec, + pub(crate) generics: Vec, +} + +impl UntaggedEnum { + pub fn variants(&self) -> impl Iterator { + self.variants.iter() + } + + pub fn generics(&self) -> impl Iterator { + self.generics.iter() + } +} + +impl Into for UntaggedEnum { + fn into(self) -> EnumType { + EnumType::Untagged(self) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct TaggedEnum { + pub(crate) variants: Vec<(Cow<'static, str>, EnumVariant)>, + pub(crate) generics: Vec, + pub(crate) repr: EnumRepr, +} + +impl TaggedEnum { + pub fn variants(&self) -> impl Iterator, EnumVariant)> { + self.variants.iter() + } + + pub fn generics(&self) -> impl Iterator { + self.generics.iter() + } + + pub fn repr(&self) -> &EnumRepr { + &self.repr + } +} + +impl Into for TaggedEnum { + fn into(self) -> EnumType { + EnumType::Tagged(self) + } +} + /// Enum type which dictates how the enum is represented. /// /// The tagging refers to the [Serde concept](https://serde.rs/enum-representations.html). @@ -12,17 +61,9 @@ use crate::{ /// [`Untagged`](EnumType::Untagged) is here rather than in [`EnumRepr`] as it is the only enum representation that does not have tags on its variants. /// Separating it allows for better typesafety since `variants` doesn't have to be a [`Vec`] of tuples. #[derive(Debug, Clone, PartialEq)] -#[allow(missing_docs)] pub enum EnumType { - Untagged { - variants: Vec, - generics: Vec, - }, - Tagged { - variants: Vec<(Cow<'static, str>, EnumVariant)>, - generics: Vec, - repr: EnumRepr, - }, + Untagged(UntaggedEnum), + Tagged(TaggedEnum), } impl From for DataType { @@ -34,15 +75,15 @@ impl From for DataType { impl EnumType { pub(crate) fn generics(&self) -> &Vec { match self { - Self::Untagged { generics, .. } => generics, - Self::Tagged { generics, .. } => generics, + Self::Untagged(UntaggedEnum { generics, .. }) => generics, + Self::Tagged(TaggedEnum { generics, .. }) => generics, } } pub(crate) fn variants_len(&self) -> usize { match self { - Self::Untagged { variants, .. } => variants.len(), - Self::Tagged { variants, .. } => variants.len(), + Self::Untagged(UntaggedEnum { variants, .. }) => variants.len(), + Self::Tagged(TaggedEnum { variants, .. }) => variants.len(), } } @@ -50,7 +91,7 @@ impl EnumType { /// This function will filter them out so types can be exported for valid variants. pub fn make_flattenable(&mut self, impl_location: ImplLocation) -> Result<(), ExportError> { match self { - Self::Untagged { variants, .. } => { + Self::Untagged(UntaggedEnum { variants, .. }) => { variants.iter().try_for_each(|v| match v { EnumVariant::Unit => Ok(()), EnumVariant::Named(_) => Ok(()), @@ -60,7 +101,7 @@ impl EnumType { )), })?; } - Self::Tagged { variants, repr, .. } => { + Self::Tagged(TaggedEnum { variants, repr, .. }) => { variants.iter().try_for_each(|(_, v)| { match repr { EnumRepr::External => match v { diff --git a/src/datatype/mod.rs b/src/datatype/mod.rs index cc8b71c..baa946c 100644 --- a/src/datatype/mod.rs +++ b/src/datatype/mod.rs @@ -118,18 +118,21 @@ impl From for DataType { impl + 'static> From> for DataType { fn from(t: Vec) -> Self { - DataType::Enum(EnumType::Untagged { - variants: t - .into_iter() - .map(|t| { - EnumVariant::Unnamed(TupleType::Named { - fields: vec![t.into()], - generics: vec![], + DataType::Enum( + UntaggedEnum { + variants: t + .into_iter() + .map(|t| { + EnumVariant::Unnamed(TupleType::Named { + fields: vec![t.into()], + generics: vec![], + }) }) - }) - .collect(), - generics: vec![], - }) + .collect(), + generics: vec![], + } + .into(), + ) } } diff --git a/src/internal.rs b/src/internal.rs index 9d064b9..680b200 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -62,4 +62,20 @@ pub mod construct { generics, } } + + pub const fn untagged_enum(variants: Vec, generics: Vec) -> EnumType { + EnumType::Untagged(UntaggedEnum { variants, generics }) + } + + pub const fn tagged_enum( + variants: Vec<(Cow<'static, str>, EnumVariant)>, + generics: Vec, + repr: EnumRepr, + ) -> EnumType { + EnumType::Tagged(TaggedEnum { + variants, + generics, + repr, + }) + } } diff --git a/src/lang/ts/mod.rs b/src/lang/ts/mod.rs index 65bc75c..26e2094 100644 --- a/src/lang/ts/mod.rs +++ b/src/lang/ts/mod.rs @@ -321,7 +321,7 @@ fn enum_datatype( } Ok(match e { - EnumType::Tagged { variants, repr, .. } => { + EnumType::Tagged(TaggedEnum { variants, repr, .. }) => { let mut variants = variants .iter() .map(|(variant_name, variant)| { @@ -376,7 +376,7 @@ fn enum_datatype( variants.dedup(); variants.join(" | ") } - EnumType::Untagged { variants, .. } => { + EnumType::Untagged(UntaggedEnum { variants, .. }) => { let mut variants = variants .iter() .map(|variant| { diff --git a/src/type/impls.rs b/src/type/impls.rs index 7ecedf4..371b8c3 100644 --- a/src/type/impls.rs +++ b/src/type/impls.rs @@ -255,23 +255,26 @@ const _: () = { impl Type for serde_json::Number { fn inline(_: DefOpts, _: &[DataType]) -> Result { - Ok(DataType::Enum(EnumType::Untagged { - variants: vec![ - EnumVariant::Unnamed(TupleType::Named { - fields: vec![DataType::Primitive(PrimitiveType::f64)], - generics: vec![], - }), - EnumVariant::Unnamed(TupleType::Named { - fields: vec![DataType::Primitive(PrimitiveType::i64)], - generics: vec![], - }), - EnumVariant::Unnamed(TupleType::Named { - fields: vec![DataType::Primitive(PrimitiveType::u64)], - generics: vec![], - }), - ], - generics: vec![], - })) + Ok(DataType::Enum( + UntaggedEnum { + variants: vec![ + EnumVariant::Unnamed(TupleType::Named { + fields: vec![DataType::Primitive(PrimitiveType::f64)], + generics: vec![], + }), + EnumVariant::Unnamed(TupleType::Named { + fields: vec![DataType::Primitive(PrimitiveType::i64)], + generics: vec![], + }), + EnumVariant::Unnamed(TupleType::Named { + fields: vec![DataType::Primitive(PrimitiveType::u64)], + generics: vec![], + }), + ], + generics: vec![], + } + .into(), + )) } } }; @@ -298,23 +301,26 @@ const _: () = { impl Type for serde_yaml::Number { fn inline(_: DefOpts, _: &[DataType]) -> Result { - Ok(DataType::Enum(EnumType::Untagged { - variants: vec![ - EnumVariant::Unnamed(TupleType::Named { - fields: vec![DataType::Primitive(PrimitiveType::f64)], - generics: vec![], - }), - EnumVariant::Unnamed(TupleType::Named { - fields: vec![DataType::Primitive(PrimitiveType::i64)], - generics: vec![], - }), - EnumVariant::Unnamed(TupleType::Named { - fields: vec![DataType::Primitive(PrimitiveType::u64)], - generics: vec![], - }), - ], - generics: vec![], - })) + Ok(DataType::Enum( + UntaggedEnum { + variants: vec![ + EnumVariant::Unnamed(TupleType::Named { + fields: vec![DataType::Primitive(PrimitiveType::f64)], + generics: vec![], + }), + EnumVariant::Unnamed(TupleType::Named { + fields: vec![DataType::Primitive(PrimitiveType::i64)], + generics: vec![], + }), + EnumVariant::Unnamed(TupleType::Named { + fields: vec![DataType::Primitive(PrimitiveType::u64)], + generics: vec![], + }), + ], + generics: vec![], + } + .into(), + )) } } }; @@ -505,7 +511,7 @@ impl_as!(url::Url as String); #[cfg(feature = "either")] impl Type for either::Either { fn inline(opts: DefOpts, generics: &[DataType]) -> Result { - Ok(DataType::Enum(EnumType::Untagged { + Ok(DataType::Enum(EnumType::Untagged(UntaggedEnum { variants: vec![ EnumVariant::Unnamed(TupleType::Named { fields: vec![L::inline( @@ -529,6 +535,6 @@ impl Type for either::Either { }), ], generics: vec![], - })) + }))) } }