In this commit, several changes were made across different files: - In `FSM.cs` and `Imm.cs`, the `[CallerArgumentExpression]` attribute was updated to reflect the correct argument names. - The `ProcessWork` method in `Imm.cs` was changed from virtual to override. - In `Log.cs`, the `[CallerArgumentExpression]` attribute was updated for clarity. - A new override for the `GetHashCode()` method was added in `AddressStack.cs`. - The version of "Microsoft.CodeAnalysis.CSharp" package reference was updated from 4.2.0 to 4.3.1 in 'SharpLib.csproj'. These changes improve code readability and ensure that methods are correctly overridden where necessary. Also, updating the package version ensures compatibility with newer features or bug fixes provided by Microsoft's C# compiler platform.
405 lines
9.8 KiB
C#
405 lines
9.8 KiB
C#
|
|
|
|
#nullable enable
|
|
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.Serialization;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using lib;
|
|
|
|
namespace imm;
|
|
|
|
/*
|
|
T O D O :
|
|
T O D O :
|
|
T O D O :
|
|
x) Add unit tests for all this. This will definitely benefit from them
|
|
*/
|
|
|
|
static public class Util
|
|
{
|
|
//This can handle both Timed and Recorded
|
|
static public T Process<T>( ref T obj, Func<T, T> fn, string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("fn")]
|
|
string dbgExp = "" )
|
|
where T : Recorded<T>
|
|
{
|
|
obj = obj.Process( fn, reason, dbgName, dbgPath, dbgLine, dbgExp );
|
|
return obj;
|
|
}
|
|
|
|
static public T LightProcess<T>( ref T obj, Func<T, T> fn,
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("fn")]
|
|
string dbgExp = ""
|
|
)
|
|
where T : Versioned<T>
|
|
{
|
|
obj = obj.Process( fn, reason );
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
public interface Meta
|
|
{
|
|
public uint Version => 0;
|
|
public string Reason => "";
|
|
public string Expression => "";
|
|
public string MemberName => "";
|
|
public string FilePath => "";
|
|
public int LineNumber => -1;
|
|
public DateTime CreatedAt => DateTime.MinValue;
|
|
public DateTime TouchedAt => DateTime.MinValue;
|
|
|
|
}
|
|
|
|
public interface Imm
|
|
{
|
|
public Meta Meta { get; }
|
|
public object Record( string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0
|
|
);
|
|
|
|
public Imm Process( Imm next,
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("next")]
|
|
string dbgExp = ""
|
|
)
|
|
{
|
|
return next;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//[lib.Ser( Types = lib.Types.None )]
|
|
public record class Versioned<T> : Imm
|
|
where T : Versioned<T>
|
|
{
|
|
|
|
public delegate void ChangeDelegate( T ZZOld, T next );
|
|
|
|
public record class MetaData : Meta
|
|
{
|
|
public uint Version { get; internal set; } = 0;
|
|
public string Reason { get; internal set; } = "";
|
|
|
|
public MetaData() { }
|
|
}
|
|
|
|
protected Versioned( )
|
|
: this( new MetaData { Version = 1, Reason = $"Versioned.cons" } )
|
|
{
|
|
}
|
|
|
|
internal Versioned( MetaData meta )
|
|
{
|
|
MetaStorage = meta;
|
|
}
|
|
|
|
virtual public T Record(
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0
|
|
)
|
|
{
|
|
return Process( t => t, reason );
|
|
}
|
|
|
|
|
|
|
|
protected MetaData MetaStorage = new();
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
public MetaData Meta => MetaStorage;
|
|
|
|
Meta Imm.Meta => MetaStorage;
|
|
|
|
[lib.Dont]
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
public ChangeDelegate OnChange = (old, cur) => {};
|
|
|
|
/*
|
|
public void AddOnChange( ChangeDelegate fn,
|
|
string reason,
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0`
|
|
)
|
|
{
|
|
log.debug( $"ADD {log.whatFile(dbgPath)}({dbgLine}): {dbgName} added OnChange bcs {reason}" );
|
|
OnChange += fn;
|
|
}
|
|
|
|
public void RemOnChange( ChangeDelegate fn,
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0
|
|
)
|
|
{
|
|
log.debug( $"REM {log.whatFile(dbgPath)}({dbgLine}): {dbgName} removing OnChange" );
|
|
OnChange -= fn;
|
|
}
|
|
*/
|
|
|
|
|
|
public T Process( Func<T, T> fn, string reason = "" )
|
|
{
|
|
var newT = fn( ( T )this );
|
|
|
|
return newT with
|
|
{
|
|
MetaStorage = Meta with
|
|
{
|
|
Version = newT.Meta.Version + 1,
|
|
Reason = reason,
|
|
}
|
|
};
|
|
}
|
|
|
|
object Imm.Record( string reason, string dbgName, string dbgPath, int dbgLine ) => Record( reason, dbgName, dbgPath, dbgLine );
|
|
|
|
//public object Record( string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = 0 ) => Recorded( );
|
|
}
|
|
|
|
//[lib.Ser( Types = lib.Types.None )]
|
|
public record class Recorded<T> : Versioned<T>, imm.Imm
|
|
where T : Recorded<T>
|
|
{
|
|
|
|
new public record class MetaData : Versioned<T>.MetaData
|
|
{
|
|
[lib.Dont]
|
|
public T? ZZOld { get; internal set; }
|
|
public T? Old => ZZOld;
|
|
public string DbgName { get; internal set; } = "";
|
|
public string DbgPath { get; internal set; } = "";
|
|
public int DbgLine { get; internal set; } = -1;
|
|
public string DbgExp { get; internal set; } = "";
|
|
|
|
public MetaData() { }
|
|
}
|
|
|
|
public Recorded() : this( new MetaData() )
|
|
{
|
|
}
|
|
|
|
public Recorded(MetaData meta) : base( meta )
|
|
{
|
|
}
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
new public MetaData Meta => MetaStorage as MetaData ?? new MetaData();
|
|
|
|
|
|
override public T Record(
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0
|
|
)
|
|
{
|
|
return Process( t => t, reason, dbgName, dbgPath, dbgLine );
|
|
}
|
|
|
|
virtual public T Process( T next,
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("next")]
|
|
string dbgExp = ""
|
|
)
|
|
{
|
|
return ProcessWork( ( old ) => next, reason, dbgName, dbgPath, dbgLine, dbgExp );
|
|
}
|
|
|
|
|
|
virtual public T Process( Func<T, T> fn,
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("fn")]
|
|
string dbgExp = ""
|
|
)
|
|
{
|
|
return ProcessWork( fn, reason, dbgName, dbgPath, dbgLine, dbgExp );
|
|
}
|
|
|
|
virtual public T ProcessWork( Func<T, T> fn,
|
|
string reason,
|
|
string dbgName,
|
|
string dbgPath,
|
|
int dbgLine,
|
|
string dbgExp
|
|
)
|
|
{
|
|
var orig = ( T )this;
|
|
|
|
var next = fn( orig );
|
|
|
|
if( object.ReferenceEquals( orig, next) )
|
|
return next;
|
|
|
|
var ret = next with
|
|
{
|
|
//Do the Versioned code here
|
|
MetaStorage = Meta with
|
|
{
|
|
Version = orig.Meta.Version + 1,
|
|
Reason = !string.IsNullOrWhiteSpace( reason ) ? reason : next.Meta.Reason,
|
|
|
|
ZZOld = orig,
|
|
DbgName = dbgName,
|
|
DbgPath = dbgPath,
|
|
DbgLine = dbgLine,
|
|
DbgExp = dbgExp
|
|
}
|
|
};
|
|
|
|
OnChange( orig, ret );
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
public record class Timed<T> : Recorded<T>, imm.Imm
|
|
where T : Timed<T>
|
|
{
|
|
|
|
new public record class MetaData : Recorded<T>.MetaData
|
|
{
|
|
public readonly DateTime CreatedAt = DateTime.Now;
|
|
public DateTime TouchedAt { get; internal set; } = DateTime.Now;
|
|
}
|
|
|
|
public Timed() : this( new MetaData() )
|
|
{
|
|
}
|
|
|
|
public Timed( MetaData meta ) : base( meta )
|
|
{
|
|
}
|
|
|
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
|
new public MetaData Meta => MetaStorage as MetaData ?? new MetaData();
|
|
|
|
public TimeSpan Since => Meta.TouchedAt - Meta.Old?.Meta.TouchedAt ?? TimeSpan.MaxValue;
|
|
|
|
public void CallOnChange()
|
|
{
|
|
OnChange( Meta.Old, (T)this );
|
|
}
|
|
|
|
override public T Record(
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0
|
|
)
|
|
{
|
|
return Process( t => t with { MetaStorage = t.Meta with { Reason = $"Record {reason}" }}, reason, dbgName, dbgPath, dbgLine );
|
|
}
|
|
|
|
override public T Process( T next,
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("next")]
|
|
string dbgExp = ""
|
|
)
|
|
{
|
|
return ProcessWork( ( old ) => next, reason, dbgName, dbgPath, dbgLine, dbgExp );
|
|
}
|
|
|
|
public U ProcessFn<U>( Func<U, U> fn,
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("fn")]
|
|
string dbgExp = ""
|
|
)
|
|
where U : T
|
|
{
|
|
return (U)ProcessWork( fn as Func<T, T>, reason, dbgName, dbgPath, dbgLine, dbgExp );
|
|
}
|
|
|
|
override public T Process( Func<T, T> fn,
|
|
string reason = "",
|
|
[CallerMemberName] string dbgName = "",
|
|
[CallerFilePath] string dbgPath = "",
|
|
[CallerLineNumber] int dbgLine = 0,
|
|
[CallerArgumentExpression("fn")]
|
|
string dbgExp = ""
|
|
)
|
|
=> ProcessWork( fn, reason, dbgName, dbgPath, dbgLine, dbgExp );
|
|
|
|
override public T ProcessWork( Func<T, T> fn,
|
|
string reason,
|
|
string dbgName,
|
|
string dbgPath,
|
|
int dbgLine,
|
|
string dbgExp
|
|
)
|
|
{
|
|
var orig = ( T )this;
|
|
|
|
var next = fn( orig );
|
|
|
|
if( object.ReferenceEquals( orig, next) )
|
|
return next;
|
|
|
|
var ret = next with
|
|
{
|
|
MetaStorage = Meta with
|
|
{
|
|
//Versioned
|
|
Version = orig.Meta.Version + 1,
|
|
Reason = !string.IsNullOrWhiteSpace( reason ) ? reason : next.Meta.Reason,
|
|
|
|
//Recorded
|
|
DbgName = dbgName,
|
|
DbgPath = dbgPath,
|
|
DbgLine = dbgLine,
|
|
DbgExp = dbgExp,
|
|
ZZOld = orig,
|
|
|
|
//Timed
|
|
TouchedAt = DateTime.Now,
|
|
}
|
|
|
|
};
|
|
|
|
if( OnChange != null)
|
|
OnChange( orig, ret );
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
}
|