Skip to content

Commit

Permalink
Drop Type::definition and regig generic handling (#207)
Browse files Browse the repository at this point in the history
* wip: not sure about this

* wip: cleanup

* fix my past mistakes

* fix macros

* Fix impls

* me can't speak
  • Loading branch information
oscartbeaumont authored Dec 25, 2023
1 parent 45ee675 commit a1bc7eb
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 82 deletions.
37 changes: 29 additions & 8 deletions macros/src/type/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,29 @@ pub fn add_type_to_where_clause(ty: &TokenStream, generics: &Generics) -> Option
}
}

type DtGenericFn = fn(&TokenStream, TokenStream) -> TokenStream;
fn dt_generic_fn(f: DtGenericFn) -> DtGenericFn {
f
}

pub fn construct_datatype(
var_ident: Ident,
ty: &Type,
generic_idents: &[(usize, &Ident)],
crate_ref: &TokenStream,
inline: bool,
) -> syn::Result<TokenStream> {
let (method, transform) = match inline {
true => (quote!(inline), quote!()),
false => (quote!(reference), quote!(.inner)),
let (method, transform, generics) = match inline {
true => (
quote!(inline),
quote!(),
dt_generic_fn(|crate_ref, tokens| quote!(#crate_ref::Generics::Provided(#tokens))),
),
false => (
quote!(reference),
quote!(.inner),
dt_generic_fn(|_, tokens| tokens),
),
};

let path = match ty {
Expand All @@ -115,10 +128,11 @@ pub fn construct_datatype(
.enumerate()
.map(|(i, _)| format_ident!("{}_{}", &var_ident, i));

let generics = generics(&crate_ref, quote!(&[#(#generic_var_idents),*]));
return Ok(quote! {
#(#elems)*

let #var_ident = <#ty as #crate_ref::Type>::#method(type_map, &[#(#generic_var_idents),*])#transform;
let #var_ident = <#ty as #crate_ref::Type>::#method(type_map, #generics)#transform;
});
}
Type::Paren(p) => {
Expand All @@ -134,10 +148,11 @@ pub fn construct_datatype(
inline,
)?;

let generics = generics(&crate_ref, quote!(&[#elem_var_ident]));
return Ok(quote! {
#elem

let #var_ident = <#ty as #crate_ref::Type>::#method(type_map, &[#elem_var_ident])#transform;
let #var_ident = <#ty as #crate_ref::Type>::#method(type_map, #generics)#transform;
});
}
Type::Ptr(TypePtr { elem, .. }) | Type::Reference(TypeReference { elem, .. }) => {
Expand All @@ -151,8 +166,9 @@ pub fn construct_datatype(
));
}
Type::Macro(m) => {
let generics = generics(&crate_ref, quote!(&[]));
return Ok(quote! {
let #var_ident = <#m as #crate_ref::Type>::#method(type_map, &[])#transform;
let #var_ident = <#m as #crate_ref::Type>::#method(type_map, #generics)#transform;
});
}
ty => {
Expand All @@ -172,10 +188,14 @@ pub fn construct_datatype(
.find(|(_, ident)| ident == &type_ident)
{
let type_ident = type_ident.to_string();
let generics = generics(
&crate_ref,
quote!(&[#crate_ref::DataType::Generic(std::borrow::Cow::Borrowed(#type_ident).into())]),
);
return Ok(quote! {
let #var_ident = generics.get(#i).cloned().unwrap_or_else(
|| {
<#generic_ident as #crate_ref::Type>::#method(type_map, &[#crate_ref::DataType::Generic(std::borrow::Cow::Borrowed(#type_ident).into())])#transform
<#generic_ident as #crate_ref::Type>::#method(type_map, #generics)#transform
},
);
});
Expand Down Expand Up @@ -218,9 +238,10 @@ pub fn construct_datatype(
.iter()
.map(|(i, _)| format_ident!("{}_{}", &var_ident, i));

let generics = generics(&crate_ref, quote!(&[#(#generic_var_idents),*]));
Ok(quote! {
#(#generic_vars)*

let #var_ident = <#ty as #crate_ref::Type>::#method(type_map, &[#(#generic_var_idents),*])#transform;
let #var_ident = <#ty as #crate_ref::Type>::#method(type_map, #generics)#transform;
})
}
18 changes: 8 additions & 10 deletions macros/src/type/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,13 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt

#[automatically_derived]
#type_impl_heading {
fn inline(type_map: &mut #crate_ref::TypeMap, generics: &[#crate_ref::DataType]) -> #crate_ref::DataType {
#inlines
}
fn inline(type_map: &mut #crate_ref::TypeMap, generics: #crate_ref::Generics) -> #crate_ref::DataType {
let generics = match generics {
#crate_ref::Generics::Definition => DEFINITION_GENERICS,
#crate_ref::Generics::Provided(generics) => generics,
};

fn definition(type_map: &mut #crate_ref::TypeMap) -> #crate_ref::DataType {
Self::inline(
type_map,
&DEFINITION_GENERICS
)
#inlines
}

fn reference(type_map: &mut #crate_ref::TypeMap, generics: &[#crate_ref::DataType]) -> #crate_ref::reference::Reference {
Expand All @@ -162,7 +160,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
#deprecated,
SID,
IMPL_LOCATION,
<Self as #crate_ref::Type>::inline(type_map, generics)
<Self as #crate_ref::Type>::inline(type_map, #crate_ref::Generics::Provided(generics))
)
}

Expand All @@ -173,7 +171,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
#deprecated,
SID,
IMPL_LOCATION,
<Self as #crate_ref::Type>::definition(type_map)
<Self as #crate_ref::Type>::inline(type_map, #crate_ref::Generics::Definition)
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/datatype/reference.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Helpers for generating [Type::reference] implementations.
use crate::{DataType, DataTypeReference, NamedType, Type, TypeMap};
use crate::{DataType, DataTypeReference, Generics, NamedType, Type, TypeMap};

/// A reference datatype.
///
Expand All @@ -12,7 +12,7 @@ pub struct Reference {

pub fn inline<T: Type + ?Sized>(type_map: &mut TypeMap, generics: &[DataType]) -> Reference {
Reference {
inner: T::inline(type_map, generics),
inner: T::inline(type_map, Generics::Provided(generics)),
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use ctor;
#[cfg(feature = "functions")]
pub use specta_macros::fn_datatype;

use crate::{DataType, DeprecatedType, Field, SpectaID, Type, TypeMap};
use crate::{DataType, DeprecatedType, Field, Generics, SpectaID, Type, TypeMap};

/// Functions used to construct `crate::datatype` types (they have private fields so can't be constructed directly).
/// We intentionally keep their fields private so we can modify them without a major version bump.
Expand Down Expand Up @@ -211,7 +211,7 @@ pub fn flatten<T: Type>(sid: SpectaID, type_map: &mut TypeMap, generics: &[DataT
panic!("Type recursion limit exceeded!");
}

let ty = T::inline(type_map, generics);
let ty = T::inline(type_map, Generics::Provided(generics));

type_map.flatten_stack.pop();

Expand Down
2 changes: 1 addition & 1 deletion src/lang/ts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn inline_ref<T: Type>(_: &T, conf: &ExportConfig) -> Output {
/// Eg. `{ demo: string; };`
pub fn inline<T: Type>(conf: &ExportConfig) -> Output {
let mut type_map = TypeMap::default();
let ty = T::inline(&mut type_map, &[]);
let ty = T::inline(&mut type_map, Generics::NONE);
is_valid_ty(&ty, &type_map)?;
let result = datatype(conf, &ty, &type_map);

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ mod static_types;
pub mod r#type;

pub use crate::serde::*;
#[doc(hidden)]
#[doc(hidden)] // TODO: Should we actually do this? I think not
pub use datatype::*;
pub use lang::*;
pub use r#type::*;
Expand Down
6 changes: 3 additions & 3 deletions src/static_types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Debug;

use crate::{DataType, Type, TypeMap};
use crate::{DataType, Generics, Type, TypeMap};

/// Easily convert a non-Specta type into a Specta compatible type.
/// This will be typed as `any` in Typescript.
Expand Down Expand Up @@ -34,7 +34,7 @@ use crate::{DataType, Type, TypeMap};
pub struct Any<T = ()>(T);

impl<T> Type for Any<T> {
fn inline(_: &mut TypeMap, _: &[DataType]) -> DataType {
fn inline(_: &mut TypeMap, _: Generics) -> DataType {
DataType::Any
}
}
Expand Down Expand Up @@ -97,7 +97,7 @@ impl<T: serde::Serialize> serde::Serialize for Any<T> {
pub struct Unknown<T = ()>(T);

impl<T> Type for Unknown<T> {
fn inline(_: &mut TypeMap, _: &[DataType]) -> DataType {
fn inline(_: &mut TypeMap, _: Generics) -> DataType {
DataType::Unknown
}
}
Expand Down
37 changes: 20 additions & 17 deletions src/type/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl<'a, T: Type> Type for &'a [T] {
}

impl<const N: usize, T: Type> Type for [T; N] {
fn inline(type_map: &mut TypeMap, generics: &[DataType]) -> DataType {
fn inline(type_map: &mut TypeMap, generics: Generics) -> DataType {
DataType::List(List {
ty: Box::new(
// TODO: This is cursed. Fix it properly!!!
Expand Down Expand Up @@ -143,13 +143,16 @@ impl<const N: usize, T: Type> Type for [T; N] {
}

impl<T: Type> Type for Option<T> {
fn inline(type_map: &mut TypeMap, generics: &[DataType]) -> DataType {
DataType::Nullable(Box::new(
generics
.get(0)
.cloned()
.unwrap_or_else(|| T::inline(type_map, generics)),
))
fn inline(type_map: &mut TypeMap, generics: Generics) -> DataType {
let mut ty = None;
if let Generics::Provided(generics) = &generics {
ty = generics.get(0).cloned()
}

DataType::Nullable(Box::new(match ty {
Some(ty) => ty,
None => T::inline(type_map, generics),
}))
}

fn reference(type_map: &mut TypeMap, generics: &[DataType]) -> Reference {
Expand All @@ -165,7 +168,7 @@ impl<T: Type> Type for Option<T> {
}

impl<T: Type, E: Type> Type for std::result::Result<T, E> {
fn inline(type_map: &mut TypeMap, generics: &[DataType]) -> DataType {
fn inline(type_map: &mut TypeMap, generics: Generics) -> DataType {
DataType::Result(Box::new((
T::inline(type_map, generics),
E::inline(type_map, generics),
Expand All @@ -183,7 +186,7 @@ impl<T: Type, E: Type> Type for std::result::Result<T, E> {
}

impl<T> Type for std::marker::PhantomData<T> {
fn inline(_: &mut TypeMap, _: &[DataType]) -> DataType {
fn inline(_: &mut TypeMap, _: Generics) -> DataType {
DataType::Literal(LiteralType::None)
}
}
Expand All @@ -195,8 +198,8 @@ impl<T> Type for std::marker::PhantomData<T> {
pub enum Infallible {}

impl<T: Type> Type for std::ops::Range<T> {
fn inline(type_map: &mut TypeMap, _generics: &[DataType]) -> DataType {
let ty = Some(T::definition(type_map));
fn inline(type_map: &mut TypeMap, _generics: Generics) -> DataType {
let ty = Some(T::inline(type_map, Generics::Definition));
DataType::Struct(StructType {
name: "Range".into(),
sid: None,
Expand Down Expand Up @@ -281,7 +284,7 @@ const _: () = {
}

impl Type for Number {
fn inline(_: &mut TypeMap, _: &[DataType]) -> DataType {
fn inline(_: &mut TypeMap, _: Generics) -> DataType {
DataType::Enum(EnumType {
name: "Number".into(),
sid: None,
Expand Down Expand Up @@ -363,14 +366,14 @@ const _: () = {
}

impl Type for serde_yaml::Mapping {
fn inline(_: &mut TypeMap, _: &[DataType]) -> DataType {
fn inline(_: &mut TypeMap, _: Generics) -> DataType {
// We don't type this more accurately because `serde_json` doesn't allow non-string map keys so neither does Specta
DataType::Unknown
}
}

impl Type for serde_yaml::value::TaggedValue {
fn inline(_: &mut TypeMap, _: &[DataType]) -> DataType {
fn inline(_: &mut TypeMap, _: Generics) -> DataType {
DataType::Map(Map {
key_ty: Box::new(DataType::Primitive(PrimitiveType::String)),
value_ty: Box::new(DataType::Unknown),
Expand All @@ -379,7 +382,7 @@ const _: () = {
}

impl Type for serde_yaml::Number {
fn inline(_: &mut TypeMap, _: &[DataType]) -> DataType {
fn inline(_: &mut TypeMap, _: Generics) -> DataType {
DataType::Enum(EnumType {
name: "Number".into(),
sid: None,
Expand Down Expand Up @@ -649,7 +652,7 @@ impl_as!(url::Url as String);

#[cfg(feature = "either")]
impl<L: Type, R: Type> Type for either::Either<L, R> {
fn inline(type_map: &mut TypeMap, generics: &[DataType]) -> DataType {
fn inline(type_map: &mut TypeMap, generics: Generics) -> DataType {
DataType::Enum(EnumType {
name: "Either".into(),
sid: None,
Expand Down
Loading

0 comments on commit a1bc7eb

Please sign in to comment.