@ -15,12 +15,12 @@ using System.IO;
using Boolean = IPA . Config . Data . Boolean ;
using System.Collections ;
using IPA.Utilities ;
using System.ComponentModel ;
using System.ComponentModel ;
#if NET3
using Net3_Proxy ;
using Array = Net3_Proxy . Array ;
#endif
[assembly: InternalsVisibleTo(IPA.Config.Stores.GeneratedStore.AssemblyVisibilityTarget)]
namespace IPA.Config.Stores
@ -107,16 +107,16 @@ namespace IPA.Config.Stores
return ret ;
}
/// <summary>
/// Creates a generated store outside of the context of the config system.
/// </summary>
/// <remarks>
/// See <see cref="Generated{T}(Config, bool)"/> for more information about how it behaves.
/// </remarks>
/// <typeparam name="T">the type to wrap</typeparam>
/// <summary>
/// Creates a generated store outside of the context of the config system.
/// </summary>
/// <remarks>
/// See <see cref="Generated{T}(Config, bool)"/> for more information about how it behaves.
/// </remarks>
/// <typeparam name="T">the type to wrap</typeparam>
/// <returns>a generated instance of <typeparamref name="T"/> implementing functionality described by <see cref="Generated{T}(Config, bool)"/></returns>
/// <seealso cref="Generated{T}(Config, bool)"/>
public static T Create < T > ( ) where T : class
public static T Create < T > ( ) where T : class
= > GeneratedStoreImpl . Create < T > ( ) ;
}
@ -139,7 +139,7 @@ namespace IPA.Config.Stores
{
void CopyFrom ( T source , bool useLock ) ;
}
internal interface IGeneratedPropertyChanged : INotifyPropertyChanged
internal interface IGeneratedPropertyChanged : INotifyPropertyChanged
{
PropertyChangedEventHandler PropertyChangedEvent { get ; }
}
@ -172,18 +172,18 @@ namespace IPA.Config.Stores
internal static MethodInfo ImplTakeReadMethod = typeof ( Impl ) . GetMethod ( nameof ( ImplTakeRead ) ) ;
public static void ImplTakeRead ( IGeneratedStore s ) = > FindImpl ( s ) . TakeRead ( ) ;
public void TakeRead ( )
public void TakeRead ( )
{
if ( ! WriteSyncObject . IsWriteLockHeld )
WriteSyncObject . EnterReadLock ( ) ;
WriteSyncObject . EnterReadLock ( ) ;
}
internal static MethodInfo ImplReleaseReadMethod = typeof ( Impl ) . GetMethod ( nameof ( ImplReleaseRead ) ) ;
public static void ImplReleaseRead ( IGeneratedStore s ) = > FindImpl ( s ) . ReleaseRead ( ) ;
public void ReleaseRead ( )
public void ReleaseRead ( )
{
if ( ! WriteSyncObject . IsWriteLockHeld )
WriteSyncObject . ExitReadLock ( ) ;
if ( ! WriteSyncObject . IsWriteLockHeld )
WriteSyncObject . ExitReadLock ( ) ;
}
internal static MethodInfo ImplTakeWriteMethod = typeof ( Impl ) . GetMethod ( nameof ( ImplTakeWrite ) ) ;
@ -200,57 +200,57 @@ namespace IPA.Config.Stores
public IDisposable ChangeTransaction ( IDisposable nest , bool takeWrite = true )
= > GetFreeTransaction ( ) . InitWith ( this , ! inChangeTransaction , nest , takeWrite & & ! WriteSyncObject . IsWriteLockHeld ) ;
private ChangeTransactionObj GetFreeTransaction ( )
= > freeTransactionObjs . Count > 0 ? freeTransactionObjs . Pop ( )
private ChangeTransactionObj GetFreeTransaction ( )
= > freeTransactionObjs . Count > 0 ? freeTransactionObjs . Pop ( )
: new ChangeTransactionObj ( ) ;
// TODO: maybe sometimes clean this?
private static readonly Stack < ChangeTransactionObj > freeTransactionObjs = new Stack < ChangeTransactionObj > ( ) ;
private sealed class ChangeTransactionObj : IDisposable
{
private struct Data
{
public readonly Impl impl ;
public readonly bool owns ;
public readonly bool ownsWrite ;
public readonly IDisposable nested ;
public Data ( Impl impl , bool owning , bool takeWrite , IDisposable nest )
{
this . impl = impl ; owns = owning ; ownsWrite = takeWrite ; nested = nest ;
}
}
private Data data ;
public ChangeTransactionObj InitWith ( Impl impl , bool owning , IDisposable nest , bool takeWrite )
{
data = new Data ( impl , owning , takeWrite , nest ) ;
if ( data . owns )
impl . inChangeTransaction = true ;
if ( data . ownsWrite )
impl . TakeWrite ( ) ;
return this ;
}
public void Dispose ( ) = > Dispose ( true ) ;
private void Dispose ( bool addToStore )
{
if ( data . owns )
{
data . impl . inChangeTransaction = false ;
data . impl . InvokeChanged ( ) ;
}
data . nested ? . Dispose ( ) ;
if ( data . ownsWrite )
data . impl . ReleaseWrite ( ) ;
if ( addToStore )
freeTransactionObjs . Push ( this ) ;
}
~ ChangeTransactionObj ( ) = > Dispose ( false ) ;
private sealed class ChangeTransactionObj : IDisposable
{
private struct Data
{
public readonly Impl impl ;
public readonly bool owns ;
public readonly bool ownsWrite ;
public readonly IDisposable nested ;
public Data ( Impl impl , bool owning , bool takeWrite , IDisposable nest )
{
this . impl = impl ; owns = owning ; ownsWrite = takeWrite ; nested = nest ;
}
}
private Data data ;
public ChangeTransactionObj InitWith ( Impl impl , bool owning , IDisposable nest , bool takeWrite )
{
data = new Data ( impl , owning , takeWrite , nest ) ;
if ( data . owns )
impl . inChangeTransaction = true ;
if ( data . ownsWrite )
impl . TakeWrite ( ) ;
return this ;
}
public void Dispose ( ) = > Dispose ( true ) ;
private void Dispose ( bool addToStore )
{
if ( data . owns )
{
data . impl . inChangeTransaction = false ;
data . impl . InvokeChanged ( ) ;
}
data . nested ? . Dispose ( ) ;
if ( data . ownsWrite )
data . impl . ReleaseWrite ( ) ;
if ( addToStore )
freeTransactionObjs . Push ( this ) ;
}
~ ChangeTransactionObj ( ) = > Dispose ( false ) ;
}
public static Impl FindImpl ( IGeneratedStore store )
@ -605,11 +605,11 @@ namespace IPA.Config.Stores
var GetLocal = MakeGetLocal ( il ) ;
foreach ( var member in structure )
{
EmitStore ( il , member , il = >
{
EmitLoad ( il , member ) ; // load the member
EmitCorrectMember ( il , member , false , true , GetLocal ) ; // correct it
{
EmitStore ( il , member , il = >
{
EmitLoad ( il , member ) ; // load the member
EmitCorrectMember ( il , member , false , true , GetLocal ) ; // correct it
} ) ;
}
@ -623,144 +623,144 @@ namespace IPA.Config.Stores
const MethodAttributes propertyMethodAttr = MethodAttributes . Public | MethodAttributes . SpecialName | MethodAttributes . HideBySig ;
const MethodAttributes virtualPropertyMethodAttr = propertyMethodAttr | MethodAttributes . Virtual | MethodAttributes . Final ;
const MethodAttributes virtualMemberMethod = MethodAttributes . Public | MethodAttributes . Virtual | MethodAttributes . HideBySig | MethodAttributes . Final ;
#region INotifyPropertyChanged
MethodBuilder notifyChanged = null ;
if ( isINotifyPropertyChanged | | hasNotifyAttribute )
{
var INotifyPropertyChanged_t = typeof ( INotifyPropertyChanged ) ;
typeBuilder . AddInterfaceImplementation ( INotifyPropertyChanged_t ) ;
var INotifyPropertyChanged_PropertyChanged =
INotifyPropertyChanged_t . GetEvent ( nameof ( INotifyPropertyChanged . PropertyChanged ) ) ;
var PropertyChangedEventHandler_t = typeof ( PropertyChangedEventHandler ) ;
var PropertyChangedEventHander_Invoke = PropertyChangedEventHandler_t . GetMethod ( nameof ( PropertyChangedEventHandler . Invoke ) ) ;
var PropertyChangedEventArgs_t = typeof ( PropertyChangedEventArgs ) ;
var PropertyChangedEventArgs_ctor = PropertyChangedEventArgs_t . GetConstructor ( new [ ] { typeof ( string ) } ) ;
var Delegate_t = typeof ( Delegate ) ;
var Delegate_Combine = Delegate_t . GetMethod ( nameof ( Delegate . Combine ) , BindingFlags . Static | BindingFlags . Public , null ,
new [ ] { Delegate_t , Delegate_t } , Array . Empty < ParameterModifier > ( ) ) ;
var Delegate_Remove = Delegate_t . GetMethod ( nameof ( Delegate . Remove ) , BindingFlags . Static | BindingFlags . Public , null ,
new [ ] { Delegate_t , Delegate_t } , Array . Empty < ParameterModifier > ( ) ) ;
var CompareExchange = typeof ( Interlocked ) . GetMethods ( )
. Where ( m = > m . Name = = nameof ( Interlocked . CompareExchange ) )
. Where ( m = > m . ContainsGenericParameters )
. Where ( m = > m . GetParameters ( ) . Length = = 3 ) . First ( )
. MakeGenericMethod ( PropertyChangedEventHandler_t ) ;
var basePropChangedEvent = type . GetEvents ( )
. Where ( e = > e . AddMethod . GetBaseDefinition ( ) . DeclaringType = = INotifyPropertyChanged_t )
. FirstOrDefault ( ) ;
var basePropChangedAdd = basePropChangedEvent ? . AddMethod ;
var basePropChangedRemove = basePropChangedEvent ? . RemoveMethod ;
var PropertyChanged_backing = typeBuilder . DefineField ( "<event>PropertyChanged" , PropertyChangedEventHandler_t , FieldAttributes . Private ) ;
var add_PropertyChanged = typeBuilder . DefineMethod ( "<add>PropertyChanged" ,
MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Final | MethodAttributes . Virtual ,
null , new [ ] { PropertyChangedEventHandler_t } ) ;
typeBuilder . DefineMethodOverride ( add_PropertyChanged , INotifyPropertyChanged_PropertyChanged . GetAddMethod ( ) ) ;
if ( basePropChangedAdd ! = null )
typeBuilder . DefineMethodOverride ( add_PropertyChanged , basePropChangedAdd ) ;
{
var il = add_PropertyChanged . GetILGenerator ( ) ;
var loopLabel = il . DefineLabel ( ) ;
var delTemp = il . DeclareLocal ( PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldfld , PropertyChanged_backing ) ;
il . MarkLabel ( loopLabel ) ;
il . Emit ( OpCodes . Stloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldflda , PropertyChanged_backing ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Call , Delegate_Combine ) ;
il . Emit ( OpCodes . Castclass , PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Call , CompareExchange ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Bne_Un_S , loopLabel ) ;
il . Emit ( OpCodes . Ret ) ;
}
var remove_PropertyChanged = typeBuilder . DefineMethod ( "<remove>PropertyChanged" ,
MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Final | MethodAttributes . Virtual ,
null , new [ ] { PropertyChangedEventHandler_t } ) ;
typeBuilder . DefineMethodOverride ( remove_PropertyChanged , INotifyPropertyChanged_PropertyChanged . GetRemoveMethod ( ) ) ;
if ( basePropChangedRemove ! = null )
typeBuilder . DefineMethodOverride ( remove_PropertyChanged , basePropChangedRemove ) ;
{
var il = remove_PropertyChanged . GetILGenerator ( ) ;
var loopLabel = il . DefineLabel ( ) ;
var delTemp = il . DeclareLocal ( PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldfld , PropertyChanged_backing ) ;
il . MarkLabel ( loopLabel ) ;
il . Emit ( OpCodes . Stloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldflda , PropertyChanged_backing ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Call , Delegate_Remove ) ;
il . Emit ( OpCodes . Castclass , PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Call , CompareExchange ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Bne_Un_S , loopLabel ) ;
il . Emit ( OpCodes . Ret ) ;
}
var PropertyChanged_event = typeBuilder . DefineEvent ( nameof ( INotifyPropertyChanged . PropertyChanged ) , EventAttributes . None , PropertyChangedEventHandler_t ) ;
PropertyChanged_event . SetAddOnMethod ( add_PropertyChanged ) ;
PropertyChanged_event . SetRemoveOnMethod ( remove_PropertyChanged ) ;
notifyChanged = typeBuilder . DefineMethod ( "<>NotifyChanged" ,
MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Final , null , new [ ] { typeof ( string ) } ) ;
{
var il = notifyChanged . GetILGenerator ( ) ;
var invokeNonNull = il . DefineLabel ( ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldfld , PropertyChanged_backing ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Brtrue , invokeNonNull ) ;
il . Emit ( OpCodes . Pop ) ;
il . Emit ( OpCodes . Ret ) ;
il . MarkLabel ( invokeNonNull ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Newobj , PropertyChangedEventArgs_ctor ) ;
il . Emit ( OpCodes . Call , PropertyChangedEventHander_Invoke ) ;
il . Emit ( OpCodes . Ret ) ;
}
}
#region INotifyPropertyChanged
MethodBuilder notifyChanged = null ;
if ( isINotifyPropertyChanged | | hasNotifyAttribute )
{
var INotifyPropertyChanged_t = typeof ( INotifyPropertyChanged ) ;
typeBuilder . AddInterfaceImplementation ( INotifyPropertyChanged_t ) ;
var INotifyPropertyChanged_PropertyChanged =
INotifyPropertyChanged_t . GetEvent ( nameof ( INotifyPropertyChanged . PropertyChanged ) ) ;
var PropertyChangedEventHandler_t = typeof ( PropertyChangedEventHandler ) ;
var PropertyChangedEventHander_Invoke = PropertyChangedEventHandler_t . GetMethod ( nameof ( PropertyChangedEventHandler . Invoke ) ) ;
var PropertyChangedEventArgs_t = typeof ( PropertyChangedEventArgs ) ;
var PropertyChangedEventArgs_ctor = PropertyChangedEventArgs_t . GetConstructor ( new [ ] { typeof ( string ) } ) ;
var Delegate_t = typeof ( Delegate ) ;
var Delegate_Combine = Delegate_t . GetMethod ( nameof ( Delegate . Combine ) , BindingFlags . Static | BindingFlags . Public , null ,
new [ ] { Delegate_t , Delegate_t } , Array . Empty < ParameterModifier > ( ) ) ;
var Delegate_Remove = Delegate_t . GetMethod ( nameof ( Delegate . Remove ) , BindingFlags . Static | BindingFlags . Public , null ,
new [ ] { Delegate_t , Delegate_t } , Array . Empty < ParameterModifier > ( ) ) ;
var CompareExchange = typeof ( Interlocked ) . GetMethods ( )
. Where ( m = > m . Name = = nameof ( Interlocked . CompareExchange ) )
. Where ( m = > m . ContainsGenericParameters )
. Where ( m = > m . GetParameters ( ) . Length = = 3 ) . First ( )
. MakeGenericMethod ( PropertyChangedEventHandler_t ) ;
var basePropChangedEvent = type . GetEvents ( )
. Where ( e = > e . Get AddMethod( ) . GetBaseDefinition ( ) . DeclaringType = = INotifyPropertyChanged_t )
. FirstOrDefault ( ) ;
var basePropChangedAdd = basePropChangedEvent ? . Get AddMethod( ) ;
var basePropChangedRemove = basePropChangedEvent ? . Get RemoveMethod( ) ;
var PropertyChanged_backing = typeBuilder . DefineField ( "<event>PropertyChanged" , PropertyChangedEventHandler_t , FieldAttributes . Private ) ;
var add_PropertyChanged = typeBuilder . DefineMethod ( "<add>PropertyChanged" ,
MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Final | MethodAttributes . Virtual ,
null , new [ ] { PropertyChangedEventHandler_t } ) ;
typeBuilder . DefineMethodOverride ( add_PropertyChanged , INotifyPropertyChanged_PropertyChanged . GetAddMethod ( ) ) ;
if ( basePropChangedAdd ! = null )
typeBuilder . DefineMethodOverride ( add_PropertyChanged , basePropChangedAdd ) ;
{
var il = add_PropertyChanged . GetILGenerator ( ) ;
var loopLabel = il . DefineLabel ( ) ;
var delTemp = il . DeclareLocal ( PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldfld , PropertyChanged_backing ) ;
il . MarkLabel ( loopLabel ) ;
il . Emit ( OpCodes . Stloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldflda , PropertyChanged_backing ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Call , Delegate_Combine ) ;
il . Emit ( OpCodes . Castclass , PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Call , CompareExchange ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Bne_Un_S , loopLabel ) ;
il . Emit ( OpCodes . Ret ) ;
}
var remove_PropertyChanged = typeBuilder . DefineMethod ( "<remove>PropertyChanged" ,
MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Final | MethodAttributes . Virtual ,
null , new [ ] { PropertyChangedEventHandler_t } ) ;
typeBuilder . DefineMethodOverride ( remove_PropertyChanged , INotifyPropertyChanged_PropertyChanged . GetRemoveMethod ( ) ) ;
if ( basePropChangedRemove ! = null )
typeBuilder . DefineMethodOverride ( remove_PropertyChanged , basePropChangedRemove ) ;
{
var il = remove_PropertyChanged . GetILGenerator ( ) ;
var loopLabel = il . DefineLabel ( ) ;
var delTemp = il . DeclareLocal ( PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldfld , PropertyChanged_backing ) ;
il . MarkLabel ( loopLabel ) ;
il . Emit ( OpCodes . Stloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldflda , PropertyChanged_backing ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Call , Delegate_Remove ) ;
il . Emit ( OpCodes . Castclass , PropertyChangedEventHandler_t ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Call , CompareExchange ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Ldloc , delTemp ) ;
il . Emit ( OpCodes . Bne_Un_S , loopLabel ) ;
il . Emit ( OpCodes . Ret ) ;
}
var PropertyChanged_event = typeBuilder . DefineEvent ( nameof ( INotifyPropertyChanged . PropertyChanged ) , EventAttributes . None , PropertyChangedEventHandler_t ) ;
PropertyChanged_event . SetAddOnMethod ( add_PropertyChanged ) ;
PropertyChanged_event . SetRemoveOnMethod ( remove_PropertyChanged ) ;
notifyChanged = typeBuilder . DefineMethod ( "<>NotifyChanged" ,
MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Final , null , new [ ] { typeof ( string ) } ) ;
{
var il = notifyChanged . GetILGenerator ( ) ;
var invokeNonNull = il . DefineLabel ( ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldfld , PropertyChanged_backing ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Brtrue , invokeNonNull ) ;
il . Emit ( OpCodes . Pop ) ;
il . Emit ( OpCodes . Ret ) ;
il . MarkLabel ( invokeNonNull ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Newobj , PropertyChangedEventArgs_ctor ) ;
il . Emit ( OpCodes . Call , PropertyChangedEventHander_Invoke ) ;
il . Emit ( OpCodes . Ret ) ;
}
}
#endregion
#region IGeneratedStore
@ -930,18 +930,18 @@ namespace IPA.Config.Stores
EmitDeserializeMember ( il , member , nextLabel , il = > il . Emit ( OpCodes . Ldloc_S , valueLocal ) , GetLocal ) ;
}
il . MarkLabel ( nextLabel ) ;
if ( notifyChanged ! = null )
{
foreach ( var member in structure )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldstr , member . Name ) ;
il . Emit ( OpCodes . Call , notifyChanged ) ;
}
}
il . MarkLabel ( nextLabel ) ;
if ( notifyChanged ! = null )
{
foreach ( var member in structure )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldstr , member . Name ) ;
il . Emit ( OpCodes . Call , notifyChanged ) ;
}
}
il . Emit ( OpCodes . Ret ) ;
}
#endregion
@ -1021,51 +1021,51 @@ namespace IPA.Config.Stores
"<>Changed" ,
virtualMemberMethod ,
null , Type . EmptyTypes ) ;
typeBuilder . DefineMethodOverride ( coreChanged , IGeneratedStore_Changed ) ;
if ( baseChanged ! = null )
typeBuilder . DefineMethodOverride ( coreChanged , IGeneratedStore_Changed ) ;
if ( baseChanged ! = null )
typeBuilder . DefineMethodOverride ( coreChanged , baseChanged ) ;
{
var il = coreChanged . GetILGenerator ( ) ;
if ( baseChanged ! = null )
if ( baseChanged ! = null )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Call , baseChanged ) ; // call base
il . Emit ( OpCodes . Call , baseChanged ) ; // call base
}
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Tailcall ) ;
il . Emit ( OpCodes . Call , Impl . ImplSignalChangedMethod ) ;
il . Emit ( OpCodes . Ret ) ; // simply call our impl's SignalChanged method and return
}
}
#endregion
#region ChangeTransaction
var coreChangeTransaction = typeBuilder . DefineMethod (
"<>ChangeTransaction" ,
virtualMemberMethod ,
typeof ( IDisposable ) , Type . EmptyTypes ) ;
typeBuilder . DefineMethodOverride ( coreChangeTransaction , IGeneratedStore_ChangeTransaction ) ;
if ( baseChangeTransaction ! = null )
typeBuilder . DefineMethodOverride ( coreChangeTransaction , baseChangeTransaction ) ;
{
var il = coreChangeTransaction . GetILGenerator ( ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
if ( baseChangeTransaction ! = null )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Call , baseChangeTransaction ) ;
}
else
il . Emit ( OpCodes . Ldnull ) ;
il . Emit ( OpCodes . Tailcall ) ;
il . Emit ( OpCodes . Call , Impl . ImplChangeTransactionMethod ) ;
il . Emit ( OpCodes . Ret ) ;
}
var coreChangeTransaction = typeBuilder . DefineMethod (
"<>ChangeTransaction" ,
virtualMemberMethod ,
typeof ( IDisposable ) , Type . EmptyTypes ) ;
typeBuilder . DefineMethodOverride ( coreChangeTransaction , IGeneratedStore_ChangeTransaction ) ;
if ( baseChangeTransaction ! = null )
typeBuilder . DefineMethodOverride ( coreChangeTransaction , baseChangeTransaction ) ;
{
var il = coreChangeTransaction . GetILGenerator ( ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
if ( baseChangeTransaction ! = null )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Call , baseChangeTransaction ) ;
}
else
il . Emit ( OpCodes . Ldnull ) ;
il . Emit ( OpCodes . Tailcall ) ;
il . Emit ( OpCodes . Call , Impl . ImplChangeTransactionMethod ) ;
il . Emit ( OpCodes . Ret ) ;
}
#endregion
#region IGeneratedStore<T>
@ -1085,9 +1085,9 @@ namespace IPA.Config.Stores
var startLock = il . DefineLabel ( ) ;
il . Emit ( OpCodes . Ldarg_2 ) ;
il . Emit ( OpCodes . Brfalse , startLock ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Call , coreChangeTransaction ) ; // take the write lock
il . Emit ( OpCodes . Brfalse , startLock ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Call , coreChangeTransaction ) ; // take the write lock
il . Emit ( OpCodes . Stloc , transactionLocal ) ;
il . MarkLabel ( startLock ) ;
@ -1108,60 +1108,60 @@ namespace IPA.Config.Stores
EmitWarnException ( il , $"Error while copying from member {member.Name}" ) ;
il . EndExceptionBlock ( ) ;
}
if ( notifyChanged ! = null )
{
foreach ( var member in structure )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldstr , member . Name ) ;
il . Emit ( OpCodes . Call , notifyChanged ) ;
}
}
}
if ( notifyChanged ! = null )
{
foreach ( var member in structure )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldstr , member . Name ) ;
il . Emit ( OpCodes . Call , notifyChanged ) ;
}
}
var endLock = il . DefineLabel ( ) ;
il . Emit ( OpCodes . Ldarg_2 ) ;
il . Emit ( OpCodes . Brfalse , endLock ) ;
il . Emit ( OpCodes . Ldloc , transactionLocal ) ;
il . Emit ( OpCodes . Brfalse , endLock ) ;
il . Emit ( OpCodes . Ldloc , transactionLocal ) ;
il . Emit ( OpCodes . Callvirt , IDisposable_Dispose ) ;
il . MarkLabel ( endLock ) ;
il . Emit ( OpCodes . Ret ) ;
}
#endregion
#endregion
#region base.CopyFrom
if ( baseCopyFrom ! = null )
{
var pubCopyFrom = typeBuilder . DefineMethod (
baseCopyFrom . Name ,
virtualMemberMethod ,
null , new [ ] { type } ) ;
typeBuilder . DefineMethodOverride ( pubCopyFrom , baseCopyFrom ) ;
{
var il = pubCopyFrom . GetILGenerator ( ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Call , coreChangeTransaction ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Ldc_I4_0 ) ;
il . Emit ( OpCodes . Call , copyFrom ) ; // call internal
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Call , baseCopyFrom ) ; // call base
il . Emit ( OpCodes . Tailcall ) ;
il . Emit ( OpCodes . Callvirt , IDisposable_Dispose ) ; // dispose transaction (which calls changed)
il . Emit ( OpCodes . Ret ) ;
}
}
#endregion
#region base.CopyFrom
if ( baseCopyFrom ! = null )
{
var pubCopyFrom = typeBuilder . DefineMethod (
baseCopyFrom . Name ,
virtualMemberMethod ,
null , new [ ] { type } ) ;
typeBuilder . DefineMethodOverride ( pubCopyFrom , baseCopyFrom ) ;
{
var il = pubCopyFrom . GetILGenerator ( ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Call , coreChangeTransaction ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Ldc_I4_0 ) ;
il . Emit ( OpCodes . Call , copyFrom ) ; // call internal
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldarg_1 ) ;
il . Emit ( OpCodes . Call , baseCopyFrom ) ; // call base
il . Emit ( OpCodes . Tailcall ) ;
il . Emit ( OpCodes . Callvirt , IDisposable_Dispose ) ; // dispose transaction (which calls changed)
il . Emit ( OpCodes . Ret ) ;
}
}
#endregion
#region Members
foreach ( var member in structure . Where ( m = > m . IsVirtual ) )
{ // IsVirtual implies !IsField
@ -1220,18 +1220,18 @@ namespace IPA.Config.Stores
EmitCorrectMember ( il , member , false , false , GetLocal ) ;
il . Emit ( OpCodes . Call , set ) ;
il . BeginFinallyBlock ( ) ;
il . BeginFinallyBlock ( ) ;
il . Emit ( OpCodes . Ldloc , transactionLocal ) ;
il . Emit ( OpCodes . Callvirt , IDisposable_Dispose ) ;
il . EndExceptionBlock ( ) ;
if ( notifyChanged ! = null )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldstr , member . Name ) ;
il . Emit ( OpCodes . Call , notifyChanged ) ;
if ( notifyChanged ! = null )
{
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Ldstr , member . Name ) ;
il . Emit ( OpCodes . Call , notifyChanged ) ;
}
il . Emit ( OpCodes . Ret ) ;
}
@ -1247,8 +1247,8 @@ namespace IPA.Config.Stores
) . Compile ( ) ;
return ( creatorDel , genType ) ;
}
}
#region Logs
private static readonly MethodInfo LogErrorMethod = typeof ( GeneratedStoreImpl ) . GetMethod ( nameof ( LogError ) , BindingFlags . NonPublic | BindingFlags . Static ) ;
internal static void LogError ( Type expected , Type found , string message )
@ -1264,9 +1264,9 @@ namespace IPA.Config.Stores
internal static void LogWarningException ( Exception exception )
{
Logger . config . Warn ( exception ) ;
}
#endregion
}
#endregion
#region Correction
private static bool NeedsCorrection ( SerializedMemberInfo member )
{
@ -1291,29 +1291,29 @@ namespace IPA.Config.Stores
il . Emit ( OpCodes . Call , member . Nullable_HasValue . GetGetMethod ( ) ) ;
il . Emit ( OpCodes . Brfalse , endLabel ) ;
il . Emit ( OpCodes . Call , member . Nullable_Value . GetGetMethod ( ) ) ;
}
// TODO: impl the rest of this
// currently the only thing for this is where expect == Map, so do generate shit
}
// TODO: impl the rest of this
// currently the only thing for this is where expect == Map, so do generate shit
var copyFrom = typeof ( IGeneratedStore < > ) . MakeGenericType ( member . Type ) . GetMethod ( nameof ( IGeneratedStore < Config > . CopyFrom ) ) ;
var noCreate = il . DefineLabel ( ) ;
var valLocal = GetLocal ( member . Type ) ;
if ( ! alwaysNew )
{
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , endLabel ) ; // our input is already something we like
var valLocal = GetLocal ( member . Type ) ;
if ( ! alwaysNew )
{
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , endLabel ) ; // our input is already something we like
}
il . Emit ( OpCodes . Stloc , valLocal ) ;
if ( ! alwaysNew )
{
EmitLoad ( il , member , il = > il . Emit ( OpCodes . Ldarg_0 ) ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , noCreate ) ;
il . Emit ( OpCodes . Pop ) ;
if ( ! alwaysNew )
{
EmitLoad ( il , member , il = > il . Emit ( OpCodes . Ldarg_0 ) ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , noCreate ) ;
il . Emit ( OpCodes . Pop ) ;
}
EmitCreateChildGenerated ( il , member . Type ) ;
il . MarkLabel ( noCreate ) ;
@ -1329,11 +1329,11 @@ namespace IPA.Config.Stores
il . Emit ( OpCodes . Newobj , member . Nullable_Construct ) ;
il . MarkLabel ( endLabel ) ;
}
}
#endregion
#region Utility
#region Utility
private delegate LocalBuilder GetLocal ( Type type , int idx = 0 ) ;
private static GetLocal MakeGetLocal ( ILGenerator il )
@ -1615,28 +1615,28 @@ namespace IPA.Config.Stores
// for now, we assume that its a generated type implementing IGeneratedStore
var IGeneratedStore_Serialize = typeof ( IGeneratedStore ) . GetMethod ( nameof ( IGeneratedStore . Serialize ) ) ;
var IGeneratedStoreT_CopyFrom = typeof ( IGeneratedStore < > ) . MakeGenericType ( member . Type )
. GetMethod ( nameof ( IGeneratedStore < object > . CopyFrom ) ) ;
if ( ! member . IsVirtual )
{
var noCreate = il . DefineLabel ( ) ;
var stlocal = GetLocal ( member . Type ) ;
// first check to make sure that this is an IGeneratedStore, because we don't control assignments to it
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , noCreate ) ;
il . Emit ( OpCodes . Stloc , stlocal ) ;
EmitCreateChildGenerated ( il , member . Type ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Ldloc , stlocal ) ;
il . Emit ( OpCodes . Ldc_I4_0 ) ;
il . Emit ( OpCodes . Callvirt , IGeneratedStoreT_CopyFrom ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Stloc , stlocal ) ;
EmitStore ( il , member , il = > il . Emit ( OpCodes . Ldloc , stlocal ) ) ;
il . MarkLabel ( noCreate ) ;
var IGeneratedStoreT_CopyFrom = typeof ( IGeneratedStore < > ) . MakeGenericType ( member . Type )
. GetMethod ( nameof ( IGeneratedStore < object > . CopyFrom ) ) ;
if ( ! member . IsVirtual )
{
var noCreate = il . DefineLabel ( ) ;
var stlocal = GetLocal ( member . Type ) ;
// first check to make sure that this is an IGeneratedStore, because we don't control assignments to it
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , noCreate ) ;
il . Emit ( OpCodes . Stloc , stlocal ) ;
EmitCreateChildGenerated ( il , member . Type ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Ldloc , stlocal ) ;
il . Emit ( OpCodes . Ldc_I4_0 ) ;
il . Emit ( OpCodes . Callvirt , IGeneratedStoreT_CopyFrom ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Stloc , stlocal ) ;
EmitStore ( il , member , il = > il . Emit ( OpCodes . Ldloc , stlocal ) ) ;
il . MarkLabel ( noCreate ) ;
}
il . Emit ( OpCodes . Callvirt , IGeneratedStore_Serialize ) ;
}
@ -1681,11 +1681,11 @@ namespace IPA.Config.Stores
var valuel = GetLocal ( srcType , 0 ) ;
var noCreate = il . DefineLabel ( ) ;
il . Emit ( OpCodes . Stloc , valuel ) ;
EmitLoad ( il , member , il = > il . Emit ( OpCodes . Ldarg_0 ) ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , noCreate ) ;
il . Emit ( OpCodes . Stloc , valuel ) ;
EmitLoad ( il , member , il = > il . Emit ( OpCodes . Ldarg_0 ) ) ;
il . Emit ( OpCodes . Dup ) ;
il . Emit ( OpCodes . Isinst , typeof ( IGeneratedStore ) ) ;
il . Emit ( OpCodes . Brtrue_S , noCreate ) ;
il . Emit ( OpCodes . Pop ) ;
EmitCreateChildGenerated ( il , member . Type ) ;
il . MarkLabel ( noCreate ) ;
@ -1760,16 +1760,16 @@ namespace IPA.Config.Stores
if ( member . IsGenericConverter )
{
var fromValueBase = member . ConverterBase . GetMethod ( nameof ( ValueConverter < int > . FromValue ) ,
new [ ] { typeof ( Value ) , typeof ( object ) } ) ;
var fromValue = member . Converter . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance )
new [ ] { typeof ( Value ) , typeof ( object ) } ) ;
var fromValue = member . Converter . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance )
. FirstOrDefault ( m = > m . GetBaseDefinition ( ) = = fromValueBase ) ? ? fromValueBase ;
il . Emit ( OpCodes . Call , fromValue ) ;
}
else
{
var fromValueBase = typeof ( IValueConverter ) . GetMethod ( nameof ( IValueConverter . FromValue ) ,
new [ ] { typeof ( Value ) , typeof ( object ) } ) ;
var fromValue = member . Converter . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance )
new [ ] { typeof ( Value ) , typeof ( object ) } ) ;
var fromValue = member . Converter . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance )
. FirstOrDefault ( m = > m . GetBaseDefinition ( ) = = fromValueBase ) ? ? fromValueBase ;
il . Emit ( OpCodes . Call , fromValue ) ;
if ( member . Type . IsValueType )