Skip to content

Commit

Permalink
Drop NamedDataTypeItem::Tuple
Browse files Browse the repository at this point in the history
  • Loading branch information
oscartbeaumont committed Sep 2, 2023
1 parent 6df6fc1 commit 2e1cbf2
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 170 deletions.
22 changes: 16 additions & 6 deletions macros/src/data_type_from/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,25 @@ use crate::utils::parse_attrs;

pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenStream> {
let DeriveInput {
ident, data, attrs, ..
ident,
data,
attrs,
generics,
..
} = &parse_macro_input::parse::<DeriveInput>(input)?;

let mut attrs = parse_attrs(attrs)?;
let container_attrs = ContainerAttr::from_attrs(&mut attrs)?;

let crate_ref = container_attrs.crate_name.unwrap_or_else(|| quote!(specta));

if generics.params.len() > 0 {
return Err(syn::Error::new_spanned(
generics,
"DataTypeFrom does not support generics",
));
}

Ok(match data {
Data::Struct(data) => match &data.fields {
Fields::Named(_) => {
Expand Down Expand Up @@ -63,7 +74,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
#[automatically_derived]
impl From<#ident> for #crate_ref::DataType {
fn from(t: #ident) -> #crate_ref::DataType {
#crate_ref::DataType::Struct(t.into())
Self::Struct(t.into())
}
}
}
Expand All @@ -72,14 +83,13 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
let fields = data.fields.iter().enumerate().map(|(i, _)| {
let i = proc_macro2::Literal::usize_unsuffixed(i);
quote!(t.#i.into())
});
}).collect::<Vec<_>>();

quote! {
#[automatically_derived]
impl From<#ident> for #crate_ref::TupleType {
fn from(t: #ident) -> #crate_ref::TupleType {
#crate_ref::internal::construct::tuple_type(
vec![],
#crate_ref::internal::construct::tuple(
vec![#(#fields),*]
)
}
Expand All @@ -88,7 +98,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
#[automatically_derived]
impl From<#ident> for #crate_ref::DataType {
fn from(t: #ident) -> #crate_ref::DataType {
#crate_ref::DataType::Tuple(t.into())
Self::Tuple(t.into())
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions macros/src/type/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub fn parse_enum(
})
.collect::<syn::Result<Vec<TokenStream>>>()?;

quote!(#crate_ref::EnumVariant::Unnamed(#crate_ref::internal::construct::tuple_type(
quote!(#crate_ref::EnumVariant::Unnamed(#crate_ref::internal::construct::unnamed_struct_fields(
vec![],
vec![#(#fields.into()),*],
)))
Expand Down Expand Up @@ -163,7 +163,7 @@ pub fn parse_enum(
})
.collect::<syn::Result<Vec<TokenStream>>>()?;

quote!(#crate_ref::EnumVariant::Named(#crate_ref::internal::construct::named_struct(vec![], vec![#(#fields),*], None)))
quote!(#crate_ref::EnumVariant::Named(#crate_ref::internal::construct::named_struct_fields(vec![], vec![#(#fields),*], None)))
}
},
))
Expand All @@ -175,7 +175,7 @@ pub fn parse_enum(
let (enum_impl, can_flatten) = match repr {
Tagged::Untagged => (
quote! {
#crate_ref::internal::construct::untagged_enum(vec![#(#variant_types),*], vec![#(#definition_generics),*])
#crate_ref::internal::construct::untagged_enum(vec![#(#definition_generics),*], vec![#(#variant_types),*])
},
data.variants
.iter()
Expand All @@ -184,8 +184,8 @@ pub fn parse_enum(
Tagged::Externally => (
quote! {
#crate_ref::internal::construct::tagged_enum(
vec![#((#variant_names.into(), #variant_types)),*],
vec![#(#definition_generics),*],
vec![#((#variant_names.into(), #variant_types)),*],
#crate_ref::EnumRepr::External
)
},
Expand All @@ -198,8 +198,8 @@ pub fn parse_enum(
Tagged::Adjacently { tag, content } => (
quote! {
#crate_ref::internal::construct::tagged_enum(
vec![#((#variant_names.into(), #variant_types)),*],
vec![#(#definition_generics),*],
vec![#((#variant_names.into(), #variant_types)),*],
#crate_ref::EnumRepr::Adjacent { tag: #tag.into(), content: #content.into() }
)
},
Expand All @@ -208,8 +208,8 @@ pub fn parse_enum(
Tagged::Internally { tag } => (
quote! {
#crate_ref::internal::construct::tagged_enum(
vec![#((#variant_names.into(), #variant_types)),*],
vec![#(#definition_generics),*],
vec![#((#variant_names.into(), #variant_types)),*],
#crate_ref::EnumRepr::Internal { tag: #tag.into() },
)
},
Expand All @@ -224,7 +224,7 @@ pub fn parse_enum(
container_attrs,
name,
quote! {
#crate_ref::NamedDataTypeItem::Enum(
#crate_ref::DataType::Enum(
#enum_impl
)
},
Expand Down
22 changes: 11 additions & 11 deletions macros/src/type/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ pub fn parse_struct(
#crate_ref::DataType::Enum(item) => {
item.make_flattenable(IMPL_LOCATION)?;
}
#crate_ref::DataType::Named(#crate_ref::NamedDataType { item: #crate_ref::NamedDataTypeItem::Enum(item), .. }) => {
item.make_flattenable(IMPL_LOCATION)?;
#crate_ref::DataType::Named(#crate_ref::NamedDataType { item, .. }) => {
if let #crate_ref::DataType::Enum(item) = &mut **item {
item.make_flattenable(IMPL_LOCATION)?;
}
}
_ => {}
}
Expand Down Expand Up @@ -164,7 +166,7 @@ pub fn parse_struct(
container_attrs,
name,
quote! {
#crate_ref::NamedDataTypeItem::Struct(#crate_ref::internal::construct::named_struct(vec![#(#definition_generics),*], vec![#(#fields),*], #tag))
#crate_ref::DataType::Struct(#crate_ref::internal::construct::named_struct(vec![#(#definition_generics),*], vec![#(#fields),*], #tag))
},
)
}
Expand Down Expand Up @@ -196,7 +198,7 @@ pub fn parse_struct(
)?;

quote! {
#crate_ref::NamedDataTypeItem::Struct(#crate_ref::internal::construct::unnamed_struct(
#crate_ref::DataType::Struct(#crate_ref::internal::construct::unnamed_struct(
vec![#(#definition_generics),*],
vec![
{
Expand Down Expand Up @@ -242,12 +244,10 @@ pub fn parse_struct(
.collect::<syn::Result<Vec<TokenStream>>>()?;

quote! {
#crate_ref::NamedDataTypeItem::Tuple(
#crate_ref::internal::construct::tuple_type(
vec![#(#definition_generics),*],
vec![#(#fields),*],
)
)
#crate_ref::DataType::Struct(#crate_ref::internal::construct::unnamed_struct(
vec![#(#definition_generics),*],
vec![#(#fields),*],
))
}
}
};
Expand All @@ -259,7 +259,7 @@ pub fn parse_struct(
container_attrs,
name,
quote! {
#crate_ref::NamedDataTypeItem::Struct(#crate_ref::internal::construct::unit_struct())
#crate_ref::DataType::Struct(#crate_ref::internal::construct::unit_struct())
},
),
};
Expand Down
47 changes: 33 additions & 14 deletions src/datatype/enum.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::borrow::Cow;

use crate::{
datatype::{DataType, StructType, TupleType},
ExportError, GenericType, ImplLocation,
datatype::DataType, ExportError, GenericType, ImplLocation, NamedDataType, StructNamedFields,
StructUnnamedFields,
};

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -66,14 +66,26 @@ pub enum EnumType {
Tagged(TaggedEnum),

Check warning on line 66 in src/datatype/enum.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> src/datatype/enum.rs:66:5 | 66 | Tagged(TaggedEnum), | ^^^^^^
}

impl From<EnumType> for DataType {
fn from(t: EnumType) -> Self {
Self::Enum(t)
impl EnumType {
/// Convert a [`EnumType`] to an anonymous [`DataType`].
pub fn to_anonymous(self) -> DataType {
DataType::Enum(self)
}
}

impl EnumType {
pub(crate) fn generics(&self) -> &Vec<GenericType> {
/// Convert a [`EnumType`] to a named [`NamedDataType`].
///
/// This can easily be converted to a [`DataType`] by putting it inside the [DataType::Named] variant.
pub fn to_named(self, name: impl Into<Cow<'static, str>>) -> NamedDataType {
NamedDataType {
name: name.into(),
comments: vec![],
deprecated: None,
ext: None,
item: Box::new(DataType::Enum(self)),
}
}

pub fn generics(&self) -> &Vec<GenericType> {

Check warning on line 88 in src/datatype/enum.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a method

warning: missing documentation for a method --> src/datatype/enum.rs:88:5 | 88 | pub fn generics(&self) -> &Vec<GenericType> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
match self {
Self::Untagged(UntaggedEnum { generics, .. }) => generics,
Self::Tagged(TaggedEnum { generics, .. }) => generics,
Expand Down Expand Up @@ -110,8 +122,8 @@ impl EnumType {
"`EnumRepr::External` with ` EnumVariant::Unit` is invalid!",
)),
EnumVariant::Unnamed(v) => match v {
TupleType { fields, .. } if fields.len() == 1 => Ok(()),
TupleType { .. } => Err(ExportError::InvalidType(
StructUnnamedFields { fields, .. } if fields.len() == 1 => Ok(()),
StructUnnamedFields { .. } => Err(ExportError::InvalidType(
impl_location,
"`EnumRepr::External` with `EnumVariant::Unnamed` containing more than a single field is invalid!",
)),
Expand All @@ -136,6 +148,12 @@ impl EnumType {
}
}

impl From<EnumType> for DataType {
fn from(t: EnumType) -> Self {
Self::Enum(t)
}
}

/// Serde representation of an enum.
///
/// Does not contain [`Untagged`](EnumType::Untagged) as that is handled by [`EnumType`].
Expand All @@ -157,17 +175,18 @@ pub enum EnumRepr {
#[allow(missing_docs)]
pub enum EnumVariant {
Unit,
Named(StructType),
Unnamed(TupleType),
// TODO: Should these be holding the `struct` types or have their own???
Named(StructNamedFields),
Unnamed(StructUnnamedFields),
}

impl EnumVariant {
/// Get the [`DataType`](crate::DataType) of the variant.
pub fn data_type(&self) -> DataType {
match self {
Self::Unit => unreachable!("Unit enum variants have no type!"), // TODO: Remove unreachable in type system + avoid following clones
Self::Unnamed(tuple_type) => tuple_type.clone().into(),
Self::Named(object_type) => object_type.clone().into(),
Self::Unnamed(tuple_type) => DataType::Struct(tuple_type.clone().into()),
Self::Named(object_type) => DataType::Struct(object_type.clone().into()),
}
}
}
12 changes: 11 additions & 1 deletion src/datatype/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ pub enum DataType {
Generic(GenericType),
}

impl DataType {
pub fn generics(&self) -> Option<Vec<GenericType>> {

Check warning on line 64 in src/datatype/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a method

warning: missing documentation for a method --> src/datatype/mod.rs:64:5 | 64 | pub fn generics(&self) -> Option<Vec<GenericType>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
match self {
Self::Struct(s) => Some(s.generics()),
Self::Enum(e) => Some(e.generics().clone()), // TODO: Cringe clone
_ => None,
}
}
}

/// A reference to a [`DataType`] that can be used before a type is resolved in order to
/// support recursive types without causing an infinite loop.
///
Expand Down Expand Up @@ -123,7 +133,7 @@ impl<T: Into<DataType> + 'static> From<Vec<T>> for DataType {
variants: t
.into_iter()
.map(|t| {
EnumVariant::Unnamed(TupleType {
EnumVariant::Unnamed(StructUnnamedFields {
fields: vec![t.into()],
generics: vec![],
})
Expand Down
62 changes: 2 additions & 60 deletions src/datatype/named.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use crate::{DataType, EnumType, GenericType, ImplLocation, SpectaID, StructType, TupleType};
use crate::{DataType, ImplLocation, SpectaID};

/// A NamedDataTypeImpl includes extra information which is only available for [NamedDataType]'s that come from a real Rust type.
#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -43,7 +43,7 @@ pub struct NamedDataType {
pub(crate) ext: Option<NamedDataTypeExt>,
/// the actual type definition.
// This field is public because we match on it in flattening code. // TODO: Review if this can be fixed when reviewing the flattening logic/error handling
pub item: NamedDataTypeItem,
pub item: Box<DataType>,
}

impl NamedDataType {
Expand All @@ -69,61 +69,3 @@ impl From<NamedDataType> for DataType {
Self::Named(t)
}
}

/// The possible types for a [`NamedDataType`].
///
/// This type will model the type of the Rust type that is being exported but be aware of the following:
/// ```rust
/// #[derive(serde::Serialize)]
/// struct Demo {}
/// // is: NamedDataTypeItem::Struct
/// // typescript: `{}`
///
/// #[derive(serde::Serialize)]
/// struct Demo2();
/// // is: NamedDataTypeItem::Tuple(TupleType::Unnamed) // TODO Fix this
/// // typescript: `[]`
///
/// #[derive(specta::Type)]
/// struct Demo3;
///// is: NamedDataTypeItem::Tuple(TupleType(_))
/// // typescript: `null`
/// ```
#[derive(Debug, Clone, PartialEq)]
pub enum NamedDataTypeItem {
/// Represents an Rust struct with named fields
Struct(StructType),
/// Represents an Rust enum
Enum(EnumType),
/// Represents an Rust struct with unnamed fields
Tuple(TupleType),
}

impl NamedDataTypeItem {
/// Converts a [`NamedDataTypeItem`] into a [`DataType`]
pub fn datatype(self) -> DataType {
match self {
Self::Struct(o) => o.into(),
Self::Enum(e) => e.into(),
Self::Tuple(t) => t.into(),
}
}

/// Returns the generics arguments for the type
pub fn generics(&self) -> Vec<GenericType> {
match self {
// Named struct
Self::Struct(s) => match s {
StructType::Unit => vec![],
StructType::Unnamed(s) => s.generics.clone(),
StructType::Named(s) => s.generics.clone(),
},
// Enum
Self::Enum(e) => e.generics().clone(),
// Struct with unnamed fields
Self::Tuple(tuple) => match tuple {
TupleType { generics, .. } => generics.clone(),
},
}
}
}
Loading

0 comments on commit 2e1cbf2

Please sign in to comment.