/* ĠCopyright Ġ( c ) Ġ 2 0 2 0 ĠDavid ĠT an zer Ċ Ċ Permission Ġis Ġhereby Ġgranted , Ġfree Ġof Ġcharge , Ġto Ġany Ġperson Ġobtaining Ġa Ġcopy Ċ of Ġthis Ġsoftware Ġand Ġassociated Ġdocumentation Ġfiles Ġ( the Ġ" Software "), Ġto Ġdeal Ċ in Ġthe ĠSoftware Ġwithout Ġrestriction , Ġincluding Ġwithout Ġlimitation Ġthe Ġrights Ċ to Ġuse , Ġcopy , Ġmodify , Ġmerge , Ġpublish , Ġdistribute , Ġsublicense , Ġand / or Ġsell Ċ copies Ġof Ġthe ĠSoftware , Ġand Ġto Ġpermit Ġpersons Ġto Ġwhom Ġthe ĠSoftware Ġis Ċ furnished Ġto Ġdo Ġso , Ġsubject Ġto Ġthe Ġfollowing Ġconditions : Ċ Ċ The Ġabove Ġcopyright Ġnotice Ġand Ġthis Ġpermission Ġnotice Ġshall Ġbe Ġincluded Ġin Ġall Ċ copies Ġor Ġsubstantial Ġportions Ġof Ġthe ĠSoftware . Ċ Ċ THE ĠSOFTWARE ĠIS ĠPROVIDED Ġ" AS ĠIS ", ĠWITHOUT ĠWARRANTY ĠOF ĠANY ĠKIND , ĠEXPRESS ĠOR Ċ IMPLIED , ĠINCLUDING ĠBUT ĠNOT ĠLIMITED ĠTO ĠTHE ĠWARRANTIES ĠOF ĠMERCHANTABILITY , Ċ FITNESS ĠFOR ĠA ĠPARTICULAR ĠPURPOSE ĠAND ĠNONINFRINGEMENT . ĠIN ĠNO ĠEVENT ĠSHALL ĠTHE Ċ AUTHORS ĠOR ĠCOPYRIGHT ĠHOLDERS ĠBE ĠLIABLE ĠFOR ĠANY ĠCLAIM , ĠDAMAGES ĠOR ĠOTHER Ċ LIABILITY , ĠWHETHER ĠIN ĠAN ĠACTION ĠOF ĠCONTRACT , ĠTORT ĠOR ĠOTHERWISE , ĠARISING ĠFROM , Ċ OUT ĠOF ĠOR ĠIN ĠCONNECTION ĠWITH ĠTHE ĠSOFTWARE ĠOR ĠTHE ĠUSE ĠOR ĠOTHER ĠDEALINGS ĠIN ĠTHE Ċ SOFTWARE . Ċ */ Ċ Ċ package Ġnet . david tan zer . k record Ċ Ċ import Ġjava . lang . reflect . Invocation Handler Ċ import Ġjava . lang . reflect . Method Ċ import Ġjava . lang . reflect . Proxy Ċ Ċ private Ġdata Ġclass ĠRecord Path ( val ĠpropertyName : ĠString , Ġval Ġrecord Values : ĠMutable Map < String , ĠAny ?> ?, Ġval Ġtype : ĠClass < *> ?) Ċ Ċ interface ĠSetter < T : ĠRecord < T >> Ġ{ Ċ ĉ fun Ġ< U > Ġset ( current Value : ĠU , ĠnewValue : ĠU ): ĠSetter < T > Ċ ĉ fun Ġ< U > Ġset ( current Value : ĠU , ĠnewValue Producer : Ġ( c : ĠU ) Ġ-> ĠU ): ĠSetter < T > Ċ } Ċ private Ġclass ĠSetter Invocation Handler < T : ĠRecord < T >>( current Values : ĠMap < String , ĠAny ? >, Ġsetter : ĠRecord Setter < T >, Ġpath : ĠList < Record Path >) Ġ: ĠInvocation Handler Ġ{ Ċ ĉ private Ġval Ġcurrent Values Ġ= Ġcurrent Values Ċ ĉ private Ġval Ġsetter Ġ= Ġsetter Ċ ĉ private Ġval Ġpath Ġ= Ġpath ĊĊ ĉ @ Throws ( Throwable :: class ) Ċ ĉ override Ġoperator Ġfun Ġinvoke ( proxy : ĠAny ?, Ġmethod : ĠMethod , Ġargs : ĠArray < Any >? ): ĠAny ? Ġ{ Ċĉ ĉ val Ġnew Path Ġ= Ġpath . to Mutable List () ĊĊĉ ĉ val Ġvalue Ġ= Ġthis . current Values [ method . name ] Ċĉ ĉ if ( value Ġis ĠRecord <* >) Ġ{ ĊĊĉĉ ĉ val Ġtype Ġ= Ġvalue . java Class . interfaces [ 0 ] Ċĉĉ ĉ val Ġrecord Values : ĠMutable Map < String , ĠAny ?> Ġ= Ġtype . declared Methods . fold ( mutable Map Of ()) Ġ{ Ġacc , Ġm Ġ-> Ċĉĉĉ ĉ if ( m . name Ġ!= Ġ" with ") Ġ{ Ċĉĉĉĉ ĉ acc [ m . name ] Ġ= Ġm . invoke ( value ) Ċĉĉĉ ĉ } Ċĉĉĉ ĉ acc Ċĉĉ ĉ } Ċĉĉ ĉ new Path . add ( Record Path ( method . name , Ġrecord Values , Ġtype )) ĊĊĉĉ ĉ setter . current Path Ġ= Ġnew Path Ċĉĉ ĉ return ĠProxy . new Proxy Instance ( Ċĉĉĉĉ ĉ Record :: class . java . class Loader , Ċĉĉĉĉ ĉ array Of < Class < *> >( type ), Ċĉĉĉĉ ĉ Setter Invocation Handler ( record Values , Ġsetter , Ġnew Path )) Ċĉ ĉ } Ġelse Ġ{ Ċĉĉ ĉ new Path . add ( Record Path ( method . name , Ġnull , Ġnull )) Ċĉ ĉ } ĊĊĉ ĉ setter . current Path Ġ= Ġnew Path Ċĉ ĉ return Ġvalue Ċ ĉ } Ċ } Ċ private Ġclass ĠRecord Setter < T : ĠRecord < T >>( type : ĠClass < T >, Ġvalues : ĠMap < String , ĠAny ?> ) Ġ: ĠSetter < T > Ġ{ Ċ ĉ val Ġtype Ġ= Ġtype Ċ ĉ val Ġvalues Ġ= Ġvalues Ċ ĉ val Ġnew Values Ġ= Ġvalues . to Mutable Map () Ċ ĉ var Ġcurrent Path : ĠList < Record Path >? Ġ= Ġnull ĊĊ ĉ override Ġfun Ġ< U > Ġset ( current Value : ĠU , ĠnewValue : ĠU ): ĠSetter < T > Ġ Ġ{ Ċĉ ĉ return Ġset ( current Value ) Ġ{ ĠnewValue Ġ} Ċ ĉ } Ċ ĉ override Ġfun Ġ< U > Ġset ( current Value : ĠU , ĠnewValue Producer : Ġ( c : ĠU ) Ġ-> ĠU ): ĠSetter < T > Ġ{ Ċĉ ĉ // FIX ME : ĠWhat Ġif Ġcurrent Ġproperty Ġis Ġnull ? Ċĉ ĉ var Ġvalues Ġ= Ġnew Values Ċĉ ĉ current Path !!. forEach Indexed Ġ{ Ġindex , Ġrecord Path Ġ-> Ċĉĉ ĉ if ( index Ġ== Ġcurrent Path !!. size - 1 ) Ġ{ Ċĉĉĉ ĉ values [ record Path . propertyName ] Ġ= ĠnewValue Producer ( current Value ) Ċĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉ ĉ values [ record Path . propertyName ] Ġ= Ġrecord Path Ċĉĉĉ ĉ values Ġ= Ġrecord Path . record Values !! Ċĉĉ ĉ } Ċĉ ĉ } Ċĉ ĉ return Ġthis Ċ ĉ } ĊĊ ĉ fun Ġprox ied Value (): ĠT Ġ{ Ċĉ ĉ return ĠProxy . new Proxy Instance ( Ċĉĉĉ ĉ Record :: class . java . class Loader , Ċĉĉĉ ĉ array Of < Class < *> >( this . type ), Ċĉĉĉ ĉ Setter Invocation Handler ( this . values , Ġthis , ĠlistOf ())) Ġas ĠT Ċ ĉ } ĊĊ ĉ fun Ġcreate NewValue (): ĠT Ġ{ Ċĉ ĉ val Ġvalues Ġ= Ġthis . new Values . map Values ( this :: map Record Values ) ĊĊĉ ĉ return ĠProxy . new Proxy Instance ( Ċĉĉĉ ĉ Record :: class . java . class Loader , Ċĉĉĉ ĉ array Of < Class < *> >( type ), Ċĉĉĉ ĉ Dynamic Invocation Handler ( type , Ġvalues )) Ġas ĠT Ċ ĉ } ĊĊ ĉ private Ġfun Ġmap Record Values ( entry : ĠMap . Entry < String , ĠAny ?> ): ĠAny ? Ġ{ Ċĉ ĉ return Ġif Ġ( entry . value Ġis ĠRecord Path ) Ġ{ Ċĉĉ ĉ val Ġrecord Values Ġ= Ġ( entry . value Ġas ĠRecord Path ). record Values !!. map Values ( this :: map Record Values ) Ċĉĉ ĉ Proxy . new Proxy Instance ( Ċĉĉĉĉ ĉ Record :: class . java . class Loader , Ċĉĉĉĉ ĉ array Of (( entry . value Ġas ĠRecord Path ). type !! ), Ċĉĉĉĉ ĉ Dynamic Invocation Handler (( entry . value Ġas ĠRecord Path ). type Ġas ĠClass < Record <* >>, Ġrecord Values )) Ċĉ ĉ } Ġelse Ġ{ Ċĉĉ ĉ entry . value Ċĉ ĉ } Ċ ĉ } Ċ } Ċ private Ġclass ĠDynamic Invocation Handler < T : ĠRecord < T >> Ġ: ĠInvocation Handler Ġ{ Ċ ĉ private Ġval Ġtype : ĠClass < T > Ċ ĉ private Ġval Ġvalues : ĠMap < String , ĠAny ?> ĊĊ ĉ constructor ( type : ĠClass < T >, Ġvalues : ĠMap < String , ĠAny ?> ) Ġ{ Ċĉ ĉ this . type Ġ= Ġtype Ċĉ ĉ this . values Ġ= Ġvalues Ċ ĉ } Ċ ĉ constructor ( type : ĠClass < T >, Ġvalue : ĠT ) Ġ Ġ{ Ċĉ ĉ this . type Ġ= Ġtype ĊĊĉ ĉ values Ġ= Ġtype . declared Methods . fold ( mutable Map Of ()) Ġ{ Ġacc , Ġm Ġ-> Ċĉĉ ĉ acc [ m . name ] Ġ= Ġm . invoke ( value ) Ċĉĉ ĉ acc Ċĉ ĉ } Ċ ĉ } Ċ ĉ @ Throws ( Throwable :: class ) Ċ ĉ override Ġoperator Ġfun Ġinvoke ( proxy : ĠAny ?, Ġmethod : ĠMethod , Ġargs : ĠArray < Any ?> ?): ĠAny ? Ġ{ Ċĉ ĉ when Ġ( method . name ) Ġ{ Ċĉĉ ĉ " with " Ġ-> Ġ{ Ċĉĉĉ ĉ val Ġsetter Ġ= ĠRecord Setter ( this . type , Ġvalues ) Ċĉĉĉ ĉ val Ġmut ator Ġ= Ġargs ! ![ 0 ] Ġas Ġ( current : ĠT , Ġsetter : ĠSetter < T >) Ġ-> ĠSetter < T > Ċĉĉĉ ĉ val Ġnew Setter Ġ= Ġmut ator ( setter . prox ied Value (), Ġsetter ) Ġas ĠRecord Setter ĊĊĉĉĉ ĉ return ĠProxy . new Proxy Instance ( Ċĉĉĉĉĉ ĉ Record :: class . java . class Loader , Ċĉĉĉĉĉ ĉ array Of < Class < *> >( this . type ), Ċĉĉĉĉĉ ĉ Dynamic Invocation Handler ( type , Ġnew Setter . create NewValue ())) Ġas ĠT Ċĉĉ ĉ } Ċĉĉ ĉ " toString " Ġ-> Ġ{ Ċĉĉĉ ĉ return Ġdefault ToString ( this . type . name , Ġvalues ) Ċĉĉ ĉ } Ċĉĉ ĉ " equals " Ġ-> Ġ{ Ċĉĉĉ ĉ val Ġother Ġ= Ġargs ! ![ 0 ] ĊĊĉĉĉ ĉ return Ġif ( other Ġ== Ġnull Ġ|| Ġ! type . isAssignableFrom ( other . java Class )) Ġ{ Ċĉĉĉĉ ĉ false Ċĉĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉĉ ĉ default Equals ( type , Ġproxy !! , Ġother ) Ċĉĉĉ ĉ } Ċĉĉ ĉ } Ċĉĉ ĉ " hashCode " Ġ-> Ġ{ Ċĉĉĉ ĉ return Ġdefault HashCode ( values ) Ċĉĉ ĉ } Ċĉĉ ĉ else Ġ-> Ġreturn Ġvalues [ method . name ] Ċĉ ĉ } Ċ ĉ } Ċ } Ċ Ċ interface ĠRecord < T : ĠRecord < T >> Ġ{ Ċ ĉ @ Jvm Default Ċ ĉ fun Ġwith ( mut ator : Ġ( current : ĠT , Ġsetter : ĠSetter < T >) Ġ-> ĠSetter < T >): ĠT Ġ{ Ġthrow ĠIllegalStateException (" Always Ġoverridden Ġby Ġdefault ") Ġ} Ċ ĉ comp anion Ġobject Ġ{ Ċĉ ĉ @ Jvm Static Ġfun Ġ< T : ĠRecord < T >> Ġfrom ( type : ĠClass < T >, Ġinitial Value : ĠT ): ĠT Ġ{ Ċĉĉ ĉ return ĠProxy . new Proxy Instance ( Ċĉĉĉĉ ĉ Record :: class . java . class Loader , Ċĉĉĉĉ ĉ array Of < Class < *> >( type ), Ċĉĉĉĉ ĉ Dynamic Invocation Handler ( type , Ġinitial Value )) Ġas ĠT Ċĉ ĉ } Ċ ĉ } Ċ Ċ }