diff --git a/imm/Imm.cs b/imm/Imm.cs index fb0138d..f4dc083 100644 --- a/imm/Imm.cs +++ b/imm/Imm.cs @@ -5,6 +5,7 @@ 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; @@ -27,19 +28,19 @@ static public class Util static public T Process( ref T obj, Func fn, string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("fn")] string dbgExp = default ) where T : Recorded { - obj = obj.Process( fn, reason, dbgName, dbgPath, lineNumber, dbgExp ); + obj = obj.Process( fn, reason, dbgName, dbgPath, dbgLine, dbgExp ); return obj; } static public T LightProcess( ref T obj, Func fn, string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("fn")] string dbgExp = default ) where T : Versioned @@ -99,9 +100,36 @@ public record class Versioned : Imm Meta Imm.Meta => MetaStorage; + ObjectIDGenerator oIdGen = new(); + + [lib.Dont] [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public ChangeDelegate OnChange = (old, cur) => {}; + internal ChangeDelegate OnChange = (old, cur) => {}; + + public void AddOnChange( ChangeDelegate fn, + string reason, + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0 + ) + { + var oid = oIdGen.GetId( fn, out var firstTime ); + log.debug( $"ADD {oid}/{firstTime} {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 + ) + { + var oid = oIdGen.GetId( fn, out var firstTime ); + log.debug( $"REM {oid}/{firstTime}{log.whatFile(dbgPath)}({dbgLine}): {dbgName} removing OnChange" ); + OnChange -= fn; + } + public T Process( Func fn, string reason = "" ) { @@ -152,29 +180,29 @@ public record class Recorded : Versioned string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int lineNumber = 0 + [CallerLineNumber] int dbgLine = 0 ) { - return Process( t => t, reason, dbgName, dbgPath, lineNumber ); + return Process( t => t, reason, dbgName, dbgPath, dbgLine ); } virtual public T Process( T next, string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("next")] string dbgExp = default ) { - return Process( ( old ) => next, reason, dbgName, dbgPath, lineNumber, dbgExp ); + return Process( ( old ) => next, reason, dbgName, dbgPath, dbgLine, dbgExp ); } virtual public T Process( Func fn, string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("fn")] string dbgExp = default ) @@ -183,6 +211,9 @@ public record class Recorded : Versioned var next = fn( orig ); + if( object.ReferenceEquals( orig, next) ) + return next; + var ret = next with { //Do the Versioned code here @@ -194,7 +225,7 @@ public record class Recorded : Versioned ZZOld = orig, MemberName = dbgName, FilePath = dbgPath, - LineNumber = lineNumber, + LineNumber = dbgLine, } }; @@ -236,35 +267,35 @@ public record class Timed : Recorded string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int lineNumber = 0 + [CallerLineNumber] int dbgLine = 0 ) { - return Process( t => t, reason, dbgName, dbgPath, lineNumber ); + 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 lineNumber = 0, + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("next")] string dbgExp = default ) { - return Process( ( old ) => next, reason, dbgName, dbgPath, lineNumber, dbgExp ); + return Process( ( old ) => next, reason, dbgName, dbgPath, dbgLine, dbgExp ); } public U ProcessFn( Func fn, string reason = "", [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("next")] string dbgExp = default ) where U : T { - return (U)ProcessFn( fn, reason, dbgName, dbgPath, lineNumber, dbgExp ); + return (U)ProcessFn( fn, reason, dbgName, dbgPath, dbgLine, dbgExp ); } override public T Process( Func fn, @@ -290,6 +321,9 @@ public record class Timed : Recorded var next = fn( orig ); + if( object.ReferenceEquals( orig, next) ) + return next; + var ret = next with { MetaStorage = Meta with @@ -310,7 +344,8 @@ public record class Timed : Recorded }; - if( OnChange != null) OnChange( orig, ret ); + if( OnChange != null) + OnChange( orig, ret ); return ret; } diff --git a/imm/iu.cs b/imm/iu.cs index 24e8809..fab13a2 100644 --- a/imm/iu.cs +++ b/imm/iu.cs @@ -16,38 +16,38 @@ static public class iu //This can handle both Timed and Recorded static public T Process( ref T obj, Func fn, string reason = "", - [CallerMemberName] string memberName = "", - [CallerFilePath] string filePath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("fn")] - string expression = default ) + string dbgExpression = default ) where T : Recorded, Imm { - obj = obj.Process( fn, reason, memberName, filePath, lineNumber, expression ); + obj = obj.Process( fn, reason, dbgName, dbgPath, dbgLine, dbgExpression ); return obj; } - static public Recorded Process( ref Recorded obj, Func fn, + static public Timed Process( ref Timed obj, Func fn, string reason = "", - [CallerMemberName] string memberName = "", - [CallerFilePath] string filePath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("fn")] - string expression = default ) - where T : Recorded, Imm + string dbgExpression = default ) + where T : Timed, Imm { - obj = obj.Process( fn, reason, memberName, filePath, lineNumber, expression ); + obj = obj.Process( fn, reason, dbgName, dbgPath, dbgLine, dbgExpression ); return obj; } static public T LightProcess( ref T obj, Func fn, string reason = "", - [CallerMemberName] string memberName = "", - [CallerFilePath] string filePath = "", - [CallerLineNumber] int lineNumber = 0, + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, [CallerArgumentExpression("fn")] - string expression = default ) + string dbgExpression = default ) where T : Versioned, Imm { obj = obj.Process( fn, reason );