Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recusion Limit - Round 2 #306

Merged
merged 14 commits into from
May 17, 2024
Merged
14 changes: 6 additions & 8 deletions macros/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,26 +79,24 @@ impl Dependencies {

impl ToTokens for Dependencies {
fn to_tokens(&self, tokens: &mut TokenStream) {
let crate_rename = &self.crate_rename;
let lines = self.dependencies.iter();

tokens.extend(quote![{
use #crate_rename::typelist::TypeList;
()#(#lines)*
}]);
tokens.extend(quote![
#(#lines;)*
NyxCode marked this conversation as resolved.
Show resolved Hide resolved
]);
}
}

impl ToTokens for Dependency {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(match self {
Dependency::Transitive { crate_rename, ty } => {
quote![.extend(<#ty as #crate_rename::TS>::dependency_types())]
quote![<#ty as #crate_rename::TS>::visit_dependencies(v)]
}
Dependency::Generics { crate_rename, ty } => {
quote![.extend(<#ty as #crate_rename::TS>::generics())]
quote![<#ty as #crate_rename::TS>::visit_generics(v)]
}
Dependency::Type(ty) => quote![.push::<#ty>()],
Dependency::Type(ty) => quote![v.visit::<#ty>()],
});
}
}
14 changes: 7 additions & 7 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@ impl DerivedTS {
#generics_fn
#output_path_fn

#[allow(clippy::unused_unit)]
fn dependency_types() -> impl #crate_rename::typelist::TypeList
fn visit_dependencies(v: &mut impl #crate_rename::TypeVisitor)
where
Self: 'static,
{
Expand Down Expand Up @@ -195,15 +194,16 @@ impl DerivedTS {
let generics = generics
.type_params()
.filter(|ty| !self.concrete.contains_key(&ty.ident))
.map(|TypeParam { ident, .. }| quote![.push::<#ident>().extend(<#ident as #crate_rename::TS>::generics())]);
.map(|TypeParam { ident, .. }| quote![
v.visit::<#ident>();
<#ident as #crate_rename::TS>::visit_generics(v);
]);
quote! {
#[allow(clippy::unused_unit)]
fn generics() -> impl #crate_rename::typelist::TypeList
fn visit_generics(v: &mut impl #crate_rename::TypeVisitor)
where
Self: 'static,
{
use #crate_rename::typelist::TypeList;
()#(#generics)*
#(#generics)*
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions ts-rs/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ mod recursive_export {

use super::export_into;
use crate::{
typelist::{TypeList, TypeVisitor},
ExportError, TS,
ExportError, TS, TypeVisitor
};

/// Exports `T` to the file specified by the `#[ts(export_to = ..)]` attribute within the given
Expand Down Expand Up @@ -85,7 +84,7 @@ mod recursive_export {
out_dir,
error: None,
};
T::dependency_types().for_each(&mut visitor);
T::visit_dependencies(&mut visitor);
NyxCode marked this conversation as resolved.
Show resolved Hide resolved

if let Some(e) = visitor.error {
Err(e)
Expand Down
118 changes: 69 additions & 49 deletions ts-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,12 @@ use std::{
pub use ts_rs_macros::TS;

pub use crate::export::ExportError;
use crate::typelist::TypeList;

#[cfg(feature = "chrono-impl")]
mod chrono;
mod export;
#[cfg(feature = "serde-json-impl")]
mod serde_json;
pub mod typelist;

/// A type which can be represented in TypeScript.
/// Most of the time, you'd want to derive this trait instead of implementing it manually.
Expand Down Expand Up @@ -422,16 +420,15 @@ pub trait TS {
/// This function will panic if the type cannot be flattened.
fn inline_flattened() -> String;

/// Returns a [`TypeList`] of all types on which this type depends.
fn dependency_types() -> impl TypeList
/// Iterates over all dependency of this type.
fn visit_dependencies(_: &mut impl TypeVisitor)
NyxCode marked this conversation as resolved.
Show resolved Hide resolved
where
Self: 'static,
{
}

/// Returns a [`TypeList`] containing all generic parameters of this type.
/// If this type is not generic, this will return an empty [`TypeList`].
fn generics() -> impl TypeList
/// Iterates over all type parameters of this type.
fn visit_generics(_: &mut impl TypeVisitor)
where
Self: 'static,
{
Expand All @@ -442,8 +439,6 @@ pub trait TS {
where
Self: 'static,
{
use crate::typelist::TypeVisitor;

let mut deps: Vec<Dependency> = vec![];
struct Visit<'a>(&'a mut Vec<Dependency>);
impl<'a> TypeVisitor for Visit<'a> {
Expand All @@ -453,7 +448,7 @@ pub trait TS {
}
}
}
Self::dependency_types().for_each(&mut Visit(&mut deps));
Self::visit_dependencies(&mut Visit(&mut deps));

deps
}
Expand Down Expand Up @@ -530,7 +525,7 @@ pub trait TS {
}

/// Manually generate bindings for this type, returning a [`String`].
/// This function does not format the output, even if the `format` feature is enabled. TODO
/// This function does not format the output, even if the `format` feature is enabled.
///
/// # Automatic Exporting
/// Types annotated with `#[ts(export)]`, together with all of their dependencies, will be
Expand Down Expand Up @@ -578,6 +573,14 @@ pub trait TS {
}
}

/// A visitor used to iterate over all dependencies or generics of a type.
/// When an instance of [`TypeVisitor`] is passed to [`TS::visit_dependencies`] or
/// [`TS::visit_generics`], the [`TypeVisitor::visit`] method will be invoked for every dependency
/// or generic parameter respectively.
pub trait TypeVisitor: Sized {
fn visit<T: TS + 'static + ?Sized>(&mut self);
}

/// A typescript type which is depended upon by other types.
/// This information is required for generating the correct import statements.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
Expand Down Expand Up @@ -630,11 +633,14 @@ macro_rules! impl_tuples {
fn inline() -> String {
panic!("tuple cannot be inlined!");
}
fn dependency_types() -> impl TypeList
fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static
{
()$(.push::<$i>())*
$(
v.visit::<$i>();
<$i>::visit_generics(v);
)*
NyxCode marked this conversation as resolved.
Show resolved Hide resolved
}
fn inline_flattened() -> String { panic!("tuple cannot be flattened") }
fn decl() -> String { panic!("tuple cannot be declared") }
Expand All @@ -656,17 +662,19 @@ macro_rules! impl_wrapper {
fn name() -> String { T::name() }
fn inline() -> String { T::inline() }
fn inline_flattened() -> String { T::inline_flattened() }
fn dependency_types() -> impl $crate::typelist::TypeList
fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static
Self: 'static,
{
T::dependency_types()
T::visit_dependencies(v);
}
fn generics() -> impl $crate::typelist::TypeList

fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static
Self: 'static,
{
((std::marker::PhantomData::<T>,), T::generics())
T::visit_generics(v);
v.visit::<T>();
}
fn decl() -> String { panic!("wrapper type cannot be declared") }
fn decl_concrete() -> String { panic!("wrapper type cannot be declared") }
Expand All @@ -683,17 +691,17 @@ macro_rules! impl_shadow {
fn name() -> String { <$s>::name() }
fn inline() -> String { <$s>::inline() }
fn inline_flattened() -> String { <$s>::inline_flattened() }
fn dependency_types() -> impl $crate::typelist::TypeList
fn visit_dependencies(v: &mut impl $crate::TypeVisitor)
where
Self: 'static
Self: 'static,
{
<$s>::dependency_types()
<$s>::visit_dependencies(v);
}
fn generics() -> impl $crate::typelist::TypeList
fn visit_generics(v: &mut impl $crate::TypeVisitor)
where
Self: 'static
Self: 'static,
{
<$s>::generics()
<$s>::visit_generics(v);
}
fn decl() -> String { <$s>::decl() }
fn decl_concrete() -> String { <$s>::decl_concrete() }
Expand All @@ -713,18 +721,19 @@ impl<T: TS> TS for Option<T> {
format!("{} | null", T::inline())
}

fn dependency_types() -> impl TypeList
fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::dependency_types()
T::visit_dependencies(v);
}

fn generics() -> impl TypeList
fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::generics().push::<T>()
T::visit_generics(v);
v.visit::<T>();
}

fn decl() -> String {
Expand All @@ -751,18 +760,22 @@ impl<T: TS, E: TS> TS for Result<T, E> {
format!("{{ Ok : {} }} | {{ Err : {} }}", T::inline(), E::inline())
}

fn dependency_types() -> impl TypeList
fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::dependency_types().extend(E::dependency_types())
T::visit_dependencies(v);
E::visit_dependencies(v);
}

fn generics() -> impl TypeList
fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::generics().push::<T>().extend(E::generics()).push::<E>()
T::visit_generics(v);
v.visit::<T>();
E::visit_generics(v);
v.visit::<E>();
}

fn decl() -> String {
Expand Down Expand Up @@ -793,18 +806,19 @@ impl<T: TS> TS for Vec<T> {
format!("Array<{}>", T::inline())
}

fn dependency_types() -> impl TypeList
fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::dependency_types()
T::visit_dependencies(v);
}

fn generics() -> impl TypeList
fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::generics().push::<T>()
T::visit_generics(v);
v.visit::<T>();
}

fn decl() -> String {
Expand Down Expand Up @@ -846,18 +860,19 @@ impl<T: TS, const N: usize> TS for [T; N] {
)
}

fn dependency_types() -> impl TypeList
fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::dependency_types()
T::visit_dependencies(v);
}

fn generics() -> impl TypeList
fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
T::generics().push::<T>()
T::visit_generics(v);
v.visit::<T>();
}

fn decl() -> String {
Expand Down Expand Up @@ -888,18 +903,22 @@ impl<K: TS, V: TS, H> TS for HashMap<K, V, H> {
format!("{{ [key: {}]: {} }}", K::inline(), V::inline())
}

fn dependency_types() -> impl TypeList
fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
K::dependency_types().extend(V::dependency_types())
K::visit_dependencies(v);
V::visit_dependencies(v);
}

fn generics() -> impl TypeList
fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
K::generics().push::<K>().extend(V::generics()).push::<V>()
K::visit_generics(v);
v.visit::<K>();
V::visit_generics(v);
v.visit::<V>();
}

fn decl() -> String {
Expand All @@ -921,18 +940,19 @@ impl<I: TS> TS for Range<I> {
format!("{{ start: {}, end: {}, }}", I::name(), I::name())
}

fn dependency_types() -> impl TypeList
fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
I::dependency_types()
I::visit_dependencies(v);
}

fn generics() -> impl TypeList
fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
I::generics().push::<I>()
I::visit_generics(v);
v.visit::<I>();
}

fn decl() -> String {
Expand Down
Loading
Loading