From 27c05443c31bf4ae67ceb0056b17ba304804217a Mon Sep 17 00:00:00 2001 From: Kevin Amado Date: Tue, 2 Apr 2024 15:50:22 -0600 Subject: [PATCH 1/5] dedup dependencies --- macros/src/deps.rs | 58 ++++++++++++++----- .../tests/enum_with_repeated_dependencies.rs | 28 +++++++++ 2 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 ts-rs/tests/enum_with_repeated_dependencies.rs diff --git a/macros/src/deps.rs b/macros/src/deps.rs index 67305394..34c8de96 100644 --- a/macros/src/deps.rs +++ b/macros/src/deps.rs @@ -1,54 +1,82 @@ +use std::collections::HashSet; + use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{Path, Type}; pub struct Dependencies { - dependencies: Vec, crate_rename: Path, + dependencies: HashSet, pub types: Vec, } +#[derive(Hash, Eq, PartialEq)] +enum Dependency { + DependencyTypes { crate_rename: Path, ty: Type }, + Generics { crate_rename: Path, ty: Type }, + Type(Type), +} + impl Dependencies { pub fn new(crate_rename: Path) -> Self { Self { - dependencies: Vec::default(), + dependencies: HashSet::default(), crate_rename, types: Vec::default(), } } + /// Adds all dependencies from the given type pub fn append_from(&mut self, ty: &Type) { - let crate_rename = &self.crate_rename; - self.dependencies - .push(quote![.extend(<#ty as #crate_rename::TS>::dependency_types())]); + self.dependencies.insert(Dependency::DependencyTypes { + crate_rename: self.crate_rename.clone(), + ty: ty.clone(), + }); + self.types.push(ty.clone()); } /// Adds the given type. pub fn push(&mut self, ty: &Type) { - let crate_rename = &self.crate_rename; - self.dependencies.push(quote![.push::<#ty>()]); - self.dependencies.push(quote![ - .extend(<#ty as #crate_rename::TS>::generics()) - ]); + self.dependencies.insert(Dependency::Type(ty.clone())); + self.dependencies.insert(Dependency::Generics { + crate_rename: self.crate_rename.clone(), + ty: ty.clone(), + }); self.types.push(ty.clone()); } pub fn append(&mut self, mut other: Dependencies) { - if !other.dependencies.is_empty() { - self.dependencies.push(quote![.extend(#other)]); + self.dependencies.extend(other.dependencies); + + if !other.types.is_empty() { + self.types.append(&mut other.types); } - self.types.append(&mut other.types); } } impl ToTokens for Dependencies { fn to_tokens(&self, tokens: &mut TokenStream) { let crate_rename = &self.crate_rename; - let lines = &self.dependencies; + let lines = self.dependencies.iter(); + tokens.extend(quote![{ use #crate_rename::typelist::TypeList; ()#(#lines)* - }]) + }]); + } +} + +impl ToTokens for Dependency { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(match self { + Dependency::DependencyTypes { crate_rename, ty } => { + quote![.extend(<#ty as #crate_rename::TS>::dependency_types())] + } + Dependency::Generics { crate_rename, ty } => { + quote![.extend(<#ty as #crate_rename::TS>::generics())] + } + Dependency::Type(ty) => quote![.push::<#ty>()], + }); } } diff --git a/ts-rs/tests/enum_with_repeated_dependencies.rs b/ts-rs/tests/enum_with_repeated_dependencies.rs new file mode 100644 index 00000000..08d4b0cb --- /dev/null +++ b/ts-rs/tests/enum_with_repeated_dependencies.rs @@ -0,0 +1,28 @@ +use ts_rs::{ + typelist::{TypeList, TypeVisitor}, + TS, +}; + +#[derive(Debug, ts_rs::TS)] +#[ts(export)] +pub enum EnumWith1Dependency { + V001(String), + V002(String), +} + +struct DependencyCounter(usize); + +impl TypeVisitor for DependencyCounter { + fn visit(&mut self) { + self.0 += 1; + } +} + +#[test] +fn dedup_deps() { + let mut dependency_counter = DependencyCounter(0); + + EnumWith1Dependency::dependency_types().for_each(&mut dependency_counter); + + assert_eq!(dependency_counter.0, 1); +} From ff790caa24448efd52003465a0bc3c21ffe2abbe Mon Sep 17 00:00:00 2001 From: Moritz Bischof Date: Tue, 9 Apr 2024 15:06:54 +0200 Subject: [PATCH 2/5] use Rc to avoid excessive cloning --- macros/src/deps.rs | 51 ++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/macros/src/deps.rs b/macros/src/deps.rs index 34c8de96..c7592e12 100644 --- a/macros/src/deps.rs +++ b/macros/src/deps.rs @@ -3,54 +3,71 @@ use std::collections::HashSet; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{Path, Type}; +use std::rc::Rc; pub struct Dependencies { - crate_rename: Path, + crate_rename: Rc, dependencies: HashSet, - pub types: Vec, + types: HashSet>, } #[derive(Hash, Eq, PartialEq)] enum Dependency { - DependencyTypes { crate_rename: Path, ty: Type }, - Generics { crate_rename: Path, ty: Type }, - Type(Type), + // A dependency on all dependencies of `ty`. + // This does not include a dependency on `ty` itself - only its dependencies! + Transitive { crate_rename: Rc, ty: Rc }, + // A dependency on all type parameters of `ty`, as returned by `TS::generics()`. + // This does not include a dependency on `ty` itself. + Generics { crate_rename: Rc, ty: Rc }, + Type(Rc), } impl Dependencies { pub fn new(crate_rename: Path) -> Self { Self { - dependencies: HashSet::default(), - crate_rename, - types: Vec::default(), + dependencies: HashSet::new(), + crate_rename: Rc::new(crate_rename), + types: HashSet::new(), } } + + pub fn used_types(&self) -> impl Iterator { + self.types.iter().map(Rc::as_ref) + } /// Adds all dependencies from the given type pub fn append_from(&mut self, ty: &Type) { - self.dependencies.insert(Dependency::DependencyTypes { + let ty = self.push_type(ty); + self.dependencies.insert(Dependency::Transitive { crate_rename: self.crate_rename.clone(), ty: ty.clone(), }); - - self.types.push(ty.clone()); } /// Adds the given type. pub fn push(&mut self, ty: &Type) { + let ty = self.push_type(ty); self.dependencies.insert(Dependency::Type(ty.clone())); self.dependencies.insert(Dependency::Generics { crate_rename: self.crate_rename.clone(), ty: ty.clone(), }); - self.types.push(ty.clone()); } - pub fn append(&mut self, mut other: Dependencies) { + pub fn append(&mut self, other: Dependencies) { self.dependencies.extend(other.dependencies); - - if !other.types.is_empty() { - self.types.append(&mut other.types); + self.types.extend(other.types); + } + + fn push_type(&mut self, ty: &Type) -> Rc { + // this can be replaces with `get_or_insert_owned` once #60896 is stabilized + match self.types.get(ty) { + None => { + let ty = Rc::new(ty.clone()); + self.types.insert(ty.clone()); + ty + }, + Some(ty) => ty.clone() } } } @@ -70,7 +87,7 @@ impl ToTokens for Dependencies { impl ToTokens for Dependency { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.extend(match self { - Dependency::DependencyTypes { crate_rename, ty } => { + Dependency::Transitive { crate_rename, ty } => { quote![.extend(<#ty as #crate_rename::TS>::dependency_types())] } Dependency::Generics { crate_rename, ty } => { From 874a49a6faa9767747313d50fcce88a148a0b635 Mon Sep 17 00:00:00 2001 From: Moritz Bischof Date: Tue, 9 Apr 2024 15:08:09 +0200 Subject: [PATCH 3/5] merge tests, add gigantic enum --- macros/src/deps.rs | 23 +- macros/src/lib.rs | 2 +- .../tests/enum_with_repeated_dependencies.rs | 28 -- ts-rs/tests/recursion_limit.rs | 242 ++++++------------ 4 files changed, 92 insertions(+), 203 deletions(-) delete mode 100644 ts-rs/tests/enum_with_repeated_dependencies.rs diff --git a/macros/src/deps.rs b/macros/src/deps.rs index c7592e12..e38c96c5 100644 --- a/macros/src/deps.rs +++ b/macros/src/deps.rs @@ -1,9 +1,8 @@ -use std::collections::HashSet; +use std::{collections::HashSet, rc::Rc}; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{Path, Type}; -use std::rc::Rc; pub struct Dependencies { crate_rename: Rc, @@ -13,12 +12,18 @@ pub struct Dependencies { #[derive(Hash, Eq, PartialEq)] enum Dependency { - // A dependency on all dependencies of `ty`. + // A dependency on all dependencies of `ty`. // This does not include a dependency on `ty` itself - only its dependencies! - Transitive { crate_rename: Rc, ty: Rc }, + Transitive { + crate_rename: Rc, + ty: Rc, + }, // A dependency on all type parameters of `ty`, as returned by `TS::generics()`. // This does not include a dependency on `ty` itself. - Generics { crate_rename: Rc, ty: Rc }, + Generics { + crate_rename: Rc, + ty: Rc, + }, Type(Rc), } @@ -30,7 +35,7 @@ impl Dependencies { types: HashSet::new(), } } - + pub fn used_types(&self) -> impl Iterator { self.types.iter().map(Rc::as_ref) } @@ -58,7 +63,7 @@ impl Dependencies { self.dependencies.extend(other.dependencies); self.types.extend(other.types); } - + fn push_type(&mut self, ty: &Type) -> Rc { // this can be replaces with `get_or_insert_owned` once #60896 is stabilized match self.types.get(ty) { @@ -66,8 +71,8 @@ impl Dependencies { let ty = Rc::new(ty.clone()); self.types.insert(ty.clone()); ty - }, - Some(ty) => ty.clone() + } + Some(ty) => ty.clone(), } } } diff --git a/macros/src/lib.rs b/macros/src/lib.rs index b4895d52..8ec15668 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -368,7 +368,7 @@ fn generate_where_clause( let is_type_param = |id: &Ident| generics.type_params().any(|p| &p.ident == id); let mut used_types = HashSet::new(); - for ty in &dependencies.types { + for ty in dependencies.used_types() { used_type_params(&mut used_types, ty, is_type_param); } used_types.into_iter() diff --git a/ts-rs/tests/enum_with_repeated_dependencies.rs b/ts-rs/tests/enum_with_repeated_dependencies.rs deleted file mode 100644 index 08d4b0cb..00000000 --- a/ts-rs/tests/enum_with_repeated_dependencies.rs +++ /dev/null @@ -1,28 +0,0 @@ -use ts_rs::{ - typelist::{TypeList, TypeVisitor}, - TS, -}; - -#[derive(Debug, ts_rs::TS)] -#[ts(export)] -pub enum EnumWith1Dependency { - V001(String), - V002(String), -} - -struct DependencyCounter(usize); - -impl TypeVisitor for DependencyCounter { - fn visit(&mut self) { - self.0 += 1; - } -} - -#[test] -fn dedup_deps() { - let mut dependency_counter = DependencyCounter(0); - - EnumWith1Dependency::dependency_types().for_each(&mut dependency_counter); - - assert_eq!(dependency_counter.0, 1); -} diff --git a/ts-rs/tests/recursion_limit.rs b/ts-rs/tests/recursion_limit.rs index f859023f..88bee3da 100644 --- a/ts-rs/tests/recursion_limit.rs +++ b/ts-rs/tests/recursion_limit.rs @@ -1,170 +1,82 @@ +use std::any::TypeId; + +use ts_rs::{ + typelist::{TypeList, TypeVisitor}, + TS, +}; + +#[rustfmt::skip] #[derive(Debug, ts_rs::TS)] -#[ts(export)] +#[ts(export, export_to = "very_big_types")] pub enum Iso4217CurrencyCode { - AED, - AFN, - ALL, - AMD, - ANG, - AOA, - ARS, - AUD, - AWG, - AZN, - BAM, - BBD, - BDT, - BGN, - BHD, - BIF, - BMD, - BND, - BOB, - BRL, - BSD, - BTN, - BWP, - BYN, - BZD, - CAD, - CDF, - CHF, - CLP, - CNY, - COP, - CRC, - CUC, - CUP, - CVE, - CZK, - DJF, - DKK, - DOP, - DZD, - EGP, - ERN, - ETB, - EUR, - FJD, - FKP, - GBP, - GEL, - GGP, - GHS, - GIP, - GMD, - GNF, - GTQ, - GYD, - HKD, - HNL, - HRK, - HTG, - HUF, - IDR, - ILS, - IMP, - INR, - IQD, - IRR, - ISK, - JEP, - JMD, - JOD, - JPY, - KES, - KGS, - KHR, - KMF, - KPW, - KRW, - KWD, - KYD, - KZT, - LAK, - LBP, - LKR, - LRD, - LSL, - LYD, - MAD, - MDL, - MGA, - MKD, - MMK, - MNT, - MOP, - MRU, - MUR, - MVR, - MWK, - MXN, - MYR, - MZN, - NAD, - NGN, - NIO, - NOK, - NPR, - NZD, - OMR, - PAB, - PEN, - PGK, - PHP, - PKR, - PLN, - PYG, - QAR, - RON, - RSD, - RUB, - RWF, - SAR, - SBD, - SCR, - SDG, - SEK, - SGD, - SHP, - SLL, - SOS, - SPL, - SRD, - STN, - SVC, - SYP, - SZL, - THB, - TJS, - TMT, - TND, - TOP, - TRY, - TTD, - TVD, - TWD, - TZS, - UAH, - UGX, - USD, - UYU, - UZS, - VEF, - VND, - VUV, - WST, - XAF, - XCD, - XDR, - XOF, - XPF, - YER, - ZAR, - ZMW, - ZWD, + AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, + BRL, BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CUC, CUP, CVE, CZK, DJF, DKK, + DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GGP, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, + HRK, HTG, HUF, IDR, ILS, IMP, INR, IQD, IRR, ISK, JEP, JMD, JOD, JPY, KES, KGS, KHR, KMF, KPW, + KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRU, MUR, + MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, + QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLL, SOS, SPL, SRD, STN, SVC, SYP, + SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TVD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VEF, VND, VUV, + WST, XAF, XCD, XDR, XOF, XPF, YER, ZAR, ZMW, ZWD, +} + +#[rustfmt::skip] +#[derive(Debug, ts_rs::TS)] +#[ts(export, export_to = "very_big_types/")] +pub enum VeryBigEnum { + V001(String), V002(String), V003(String), V004(String), V005(String), V006(String), V007(String), + V008(String), V009(String), V010(String), V011(String), V012(String), V013(String), V014(String), + V015(String), V016(String), V017(String), V018(String), V019(String), V020(String), V021(String), + V022(String), V023(String), V024(String), V025(String), V026(String), V027(String), V028(String), + V029(String), V030(String), V031(String), V032(String), V033(String), V034(String), V035(String), + V036(String), V037(String), V038(String), V039(String), V040(String), V041(String), V042(String), + V043(String), V044(String), V045(String), V046(String), V047(String), V048(String), V049(String), + V050(String), V051(String), V052(String), V053(String), V054(String), V055(String), V056(String), + V057(String), V058(String), V059(String), V060(String), V061(String), V062(String), V063(String), + V064(String), V065(String), V066(String), V067(String), V068(String), V069(String), V070(String), + V071(String), V072(String), V073(String), V074(String), V075(String), V076(String), V077(String), + V078(String), V079(String), V080(String), V081(String), V082(String), V083(String), V084(String), + V085(String), V086(String), V087(String), V088(String), V089(String), V090(String), V091(String), + V092(String), V093(String), V094(String), V095(String), V096(String), V097(String), V098(String), + V099(String), V100(String), V101(String), V102(String), V103(String), V104(String), V105(String), + V106(String), V107(String), V108(String), V109(String), V110(String), V111(String), V112(String), + V113(String), V114(String), V115(String), V116(String), V117(String), V118(String), V119(String), + V120(String), V121(String), V122(String), V123(String), V124(String), V125(String), V126(String), + V127(String), V128(String), V129(String), V130(String), V131(String), V132(String), V133(String), + V134(String), V135(String), V136(String), V137(String), V138(String), V139(String), V140(String), + V141(String), V142(String), V143(String), V144(String), V145(String), V146(String), V147(String), + V148(String), V149(String), V150(String), V151(String), V152(String), V153(String), V154(String), + V155(String), V156(String), V157(String), V158(String), V159(String), V160(String), V161(String), + V162(String), V163(String), V164(String), V165(String), V166(String), V167(String), V168(String), + V169(String), V170(String), V171(String), V172(String), V173(String), V174(String), V175(String), + V176(String), V177(String), V178(String), V179(String), V180(String), V181(String), V182(String), + V183(String), V184(String), V185(String), V186(String), V187(String), V188(String), V189(String), + V190(String), V191(String), V192(String), V193(String), V194(String), V195(String), V196(String), + V197(String), V198(String), V199(String), V200(String), V201(String), V202(String), V203(String), + V204(String), V205(String), V206(String), V207(String), V208(String), V209(String), V210(String), + V211(String), V212(String), V213(String), V214(String), V215(String), V216(String), V217(String), + V218(String), V219(String), V220(String), V221(String), V222(String), V223(String), V224(String), + V225(String), V226(String), V227(String), V228(String), V229(String), V230(String), V231(String), + V232(String), V233(String), V234(String), V235(String), V236(String), V237(String), V238(String), + V239(String), V240(String), V241(String), V242(String), V243(String), V244(String), V245(String), + V246(String), V247(String), V248(String), V249(String), V250(String), V251(String), V252(String), + V253(String), V254(String), V255(String), V256(String), } -fn main() { - println!("{:?}", Iso4217CurrencyCode::USD) +#[test] +fn very_big_enum() { + struct Visitor(bool); + + impl TypeVisitor for Visitor { + fn visit(&mut self) { + assert!(!self.0, "there must only be one dependency"); + assert_eq!(TypeId::of::(), TypeId::of::()); + self.0 = true; + } + } + + let mut visitor = Visitor(false); + VeryBigEnum::dependencies().for_each(&mut visitor); + + assert!(visitor.0, "there must be at least one dependency"); } From 17fbe0972b88d7cdf6c62fe8ee8a25cf2b33f301 Mon Sep 17 00:00:00 2001 From: Moritz Bischof Date: Tue, 9 Apr 2024 15:09:37 +0200 Subject: [PATCH 4/5] fix test --- ts-rs/tests/recursion_limit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts-rs/tests/recursion_limit.rs b/ts-rs/tests/recursion_limit.rs index 88bee3da..d06eba68 100644 --- a/ts-rs/tests/recursion_limit.rs +++ b/ts-rs/tests/recursion_limit.rs @@ -60,7 +60,7 @@ pub enum VeryBigEnum { V232(String), V233(String), V234(String), V235(String), V236(String), V237(String), V238(String), V239(String), V240(String), V241(String), V242(String), V243(String), V244(String), V245(String), V246(String), V247(String), V248(String), V249(String), V250(String), V251(String), V252(String), - V253(String), V254(String), V255(String), V256(String), + V253(String), V254(String), V255(String), V256(String), } #[test] @@ -76,7 +76,7 @@ fn very_big_enum() { } let mut visitor = Visitor(false); - VeryBigEnum::dependencies().for_each(&mut visitor); + VeryBigEnum::dependency_types().for_each(&mut visitor); assert!(visitor.0, "there must be at least one dependency"); } From 6c3b0cb4dbd7434957c2ed027ef0fa55cf001810 Mon Sep 17 00:00:00 2001 From: Moritz Bischof Date: Tue, 9 Apr 2024 15:16:37 +0200 Subject: [PATCH 5/5] fix test --- ts-rs/tests/recursion_limit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts-rs/tests/recursion_limit.rs b/ts-rs/tests/recursion_limit.rs index d06eba68..1f0f98ae 100644 --- a/ts-rs/tests/recursion_limit.rs +++ b/ts-rs/tests/recursion_limit.rs @@ -7,7 +7,7 @@ use ts_rs::{ #[rustfmt::skip] #[derive(Debug, ts_rs::TS)] -#[ts(export, export_to = "very_big_types")] +#[ts(export, export_to = "very_big_types/")] pub enum Iso4217CurrencyCode { AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CUC, CUP, CVE, CZK, DJF, DKK,