diff --git a/SharpLib.csproj b/SharpLib.csproj index 50e9c31..9926905 100644 --- a/SharpLib.csproj +++ b/SharpLib.csproj @@ -1,7 +1,7 @@ - net9 + net9.0;net10.0 lib 0.0.1.0 0.0.1.0 diff --git a/exp/Exp.cs b/exp/Exp.cs index bb86539..6a58bab 100644 --- a/exp/Exp.cs +++ b/exp/Exp.cs @@ -1,11 +1,10 @@ using System.Collections.Immutable; using System.Runtime.CompilerServices; -using imm; namespace exp; -abstract public record class Exp : imm.Versioned> +abstract public record class Exp : io.Versioned> { protected Exp() : diff --git a/imm/FSM.cs b/imm/FSM.cs index 33e163b..3f066bf 100644 --- a/imm/FSM.cs +++ b/imm/FSM.cs @@ -5,24 +5,24 @@ using System.Runtime.CompilerServices; /// /// Base context for an FSM. -/// MUST inherit from imm.Recorded or Timed in your concrete class. +/// MUST inherit from io.Recorded or Timed in your concrete class. /// /// The concrete Context type. -public abstract record class FsmContextBase : imm.Recorded +public abstract record class FsmContextBase : io.Recorded where TSelf : FsmContextBase { // Required for 'with' expressions. - protected FsmContextBase(imm.Recorded original) : base(original) { } + protected FsmContextBase(io.Recorded original) : base(original) { } protected FsmContextBase() { } } /// /// Base state for an FSM. -/// MUST inherit from imm.Recorded or Timed in your concrete class. +/// MUST inherit from io.Recorded or Timed in your concrete class. /// /// The concrete State type. /// The concrete Context type (must be based on FsmContextBase). -public abstract record class FsmStateBase : imm.Recorded +public abstract record class FsmStateBase : io.Recorded where TSelf : FsmStateBase where TCtx : FsmContextBase { @@ -43,18 +43,18 @@ public abstract record class FsmStateBase : imm.Recorded } // Required for 'with' expressions. - protected FsmStateBase(imm.Recorded original) : base(original) { } + protected FsmStateBase(io.Recorded original) : base(original) { } protected FsmStateBase() { } } /// /// An immutable FSM base class. -/// MUST inherit from imm.Recorded or Timed in your concrete class. +/// MUST inherit from io.Recorded or Timed in your concrete class. /// /// The concrete FSM type. /// The concrete State type. /// The concrete Context type. -public abstract record class FsmBase : imm.Recorded +public abstract record class FsmBase : io.Recorded where TSelf : FsmBase where TState : FsmStateBase where TCtx : FsmContextBase @@ -69,7 +69,7 @@ public abstract record class FsmBase : imm.Recorded } // Required for 'with' expressions. - protected FsmBase(imm.Recorded original) : base(original) + protected FsmBase(io.Recorded original) : base(original) { var o = original as FsmBase; Context = o!.Context; @@ -78,7 +78,7 @@ public abstract record class FsmBase : imm.Recorded /// /// Transitions the FSM. It automatically uses the 'Process' - /// method appropriate for imm.Recorded or Timed, thanks to virtual overrides. + /// method appropriate for io.Recorded or Timed, thanks to virtual overrides. /// public TSelf Transition( TState newState, @@ -93,7 +93,7 @@ public abstract record class FsmBase : imm.Recorded var (ctxAfterExit, stateAfterExit) = State.OnExit(Context, newState); var (ctxAfterEnter, stateAfterEnter) = newState.OnEnter(ctxAfterExit, stateAfterExit); - // Since 'this' is at least 'imm.Recorded', we can call the + // Since 'this' is at least 'io.Recorded', we can call the // detailed 'Process'. If 'this' is actually 'Timed', C#'s // virtual dispatch will call the 'Timed' override automatically. return Process( @@ -106,4 +106,4 @@ public abstract record class FsmBase : imm.Recorded memberName, filePath, lineNumber, expression ); } -} \ No newline at end of file +} diff --git a/imm/Imm.cs b/imm/Imm.cs index efacaec..5fc8745 100644 --- a/imm/Imm.cs +++ b/imm/Imm.cs @@ -1,366 +1,30 @@ -#nullable enable +//#nullable enable using System; -using System.Collections.Generic; -using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Text.Json.Serialization; - -namespace imm; /// -/// Represents the base interface for versioned, immutable objects. -/// Provides access to metadata and potentially the previous version. +/// Helper static class for processing immutable objects using a 'ref' pattern. +/// Provides different levels of processing based on the type. /// -public interface Obj +public static class imm { /// - /// Gets the base metadata associated with this version. + /// Processes a 'Versioned' object (Level 1). /// - Metadata_Versioned Meta { get; } - - /// - /// Gets the previous version as a base object, if available. - /// Returns null if this is the first version or if history is not tracked. - /// - Obj? Old { get; } - - /// - /// Creates a new version without functional change. - /// Returns the new version as an Obj. - /// - Obj Record( - string reason = "Recorded", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0 ); -} - - -/// -/// Obj delegate for change notifications. -/// -public delegate void ChangeDelegate( T? oldVersion, T newVersion ); - - -/// -/// Represents a generic interface for immutable objects, -/// providing access to basic processing functions and change notifications. -/// -public interface Obj : Obj where T : Obj -{ - /// - /// Gets the change delegate associated with this object. - /// - [JsonIgnore] - ChangeDelegate OnChange { get; set; } - - /// - /// Applies a transformation and creates a new version using basic processing. - /// - T Process( + public static T LightProcess( + ref T obj, Func fn, - string reason = "Processed", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0, - [CallerArgumentExpression( "fn" )] string expStr = "" ); - - - /// - /// Creates a new version without a functional change using basic processing. - /// Uses 'new' to provide a type-safe return. - /// - new T Record( - string reason = "Recorded", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0 ); -} - - -/* -static public class ObjExtensions -{ - /// - /// Creates a new version of the object with the specified reason. - /// - public static T Record( this T obj, string reason = "Recorded" ) where T : Obj + string reason = "Processed" ) + where T : io.Versioned { - if( obj is Recorded recorded ) - { - return recorded.Record( reason ); - } - else if( obj is Versioned versioned ) - { - return versioned.Record( reason ); - } - else - { - // Dont care - - return obj; - } - } -} -*/ - -// --- Metadata Hierarchy --- - -public interface VersionedMeta -{ - public uint Version { get; } - public string Reason { get; } -} - - -/// -/// Obj metadata for version tracking. -/// -public record Metadata_Versioned -{ - public uint Version { get; init; } = 1; - public string Reason { get; init; } = "Created"; -} - - -public interface RecordedMeta : VersionedMeta -{ - public string MemberName { get; } - public string FilePath { get; } - public int LineNumber { get; } - public string Expression { get; } -} - - -/// -/// Metadata for version and recording (debug/caller info, history). -/// -public record Metadata_Recorded : Metadata_Versioned, RecordedMeta -{ - internal object? OldObject { get; init; } = null; - public string MemberName { get; init; } = ""; - public string FilePath { get; init; } = ""; - public int LineNumber { get; init; } = 0; - public string Expression { get; init; } = ""; -} - -public interface TimedMeta : RecordedMeta -{ - public DateTime CreatedAt { get; } - public DateTime TouchedAt { get; } -} - - -/// -/// Metadata for version, recording, and timing. -/// -public record Metadata_Timed : Metadata_Recorded, TimedMeta -{ - public DateTime CreatedAt { get; init; } = DateTime.UtcNow; - public DateTime TouchedAt { get; init; } = DateTime.UtcNow; -} - -// --- Record Hierarchy --- - -/// -/// Level 1: Basic versioning. Implements Obj. -/// -public record class Versioned : Obj where T : Versioned -{ - public Metadata_Versioned Meta { get; init; } = new(); - - [DebuggerBrowsable( DebuggerBrowsableState.Never )] - [JsonIgnore] - public ChangeDelegate OnChange { get; set; } = ( o, n ) => { }; - - public virtual Obj? Old => null; - - Metadata_Versioned Obj.Meta => this.Meta; - [JsonIgnore] - Obj? Obj.Old => this.Old; - - public Versioned() { } - protected Versioned( Versioned original ) - { - OnChange = original.OnChange; - Meta = original.Meta; - } - - public virtual T Process( - Func fn, - string reason = "Processed", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0, - [CallerArgumentExpression( "fn" )] string expStr = "" ) - { - var current = (T)this; - var next = fn( current ); - - if( ReferenceEquals( current, next ) ) - return current; - - var newVersion = next with - { - Meta = new Metadata_Versioned { /*...*/ }, - OnChange = current.OnChange - }; - newVersion.OnChange( current, newVersion ); - return newVersion; + obj = obj.Process( fn, reason ); + return obj; } /// - /// Basic Record. Made virtual. Implements Obj.Record. + /// Processes a 'Recorded' object (Level 2), capturing caller info. /// - public virtual T Record( - string reason = "Recorded", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0 ) => Process( t => t, reason, dbgName, dbgPath, dbgLine ); - - /// - /// Implements Obj.Record by calling the virtual T Record. - /// - Obj Obj.Record( - string reason = "Recorded", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0 ) => this.Record( reason, dbgName, dbgPath, dbgLine ); - - -} - -/// -/// Level 2: Adds history and caller info. -/// -public record class Recorded : Versioned where T : Recorded -{ - new public Metadata_Recorded Meta { get; init; } = new(); - - [JsonIgnore] - new public T? Old => Meta.OldObject as T; - - //public override Obj? Old => this.Old; - //Metadata_Versioned Obj.Meta => this.Meta; - - public Recorded() { } - protected Recorded( Recorded original ) : base( original ) { Meta = original.Meta; } - - public override T Process( - Func fn, - string reason = "", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0, - [CallerArgumentExpression( "fn" )] string expStr = "" ) - { - var current = (T)this; - var next = fn( current ); - - if( ReferenceEquals( current, next ) ) - return current; - - var newMeta = current.Meta with { - Version = current.Meta.Version + 1, - Reason = reason, - MemberName = dbgName, - FilePath = dbgPath, - LineNumber = dbgLine, - Expression = expStr, - OldObject = current, - }; - - var newVersion = next with { Meta = newMeta, OnChange = current.OnChange }; - newVersion.OnChange( current, newVersion ); - return newVersion; - } - - public new T Record( - string reason = "Recorded", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0 ) - { - return Process( t => t, reason, dbgName, dbgPath, dbgLine ); - } - -} - -/// -/// Level 3: Adds timestamps. -/// -public record class Timed : Recorded where T : Timed -{ - new public Metadata_Timed Meta { get; init; } = new(); - //Metadata_Versioned Obj.Meta => this.Meta; - public TimeSpan SinceLastTouch => Meta.TouchedAt - ( Old?.Meta as Metadata_Timed )?.TouchedAt ?? TimeSpan.Zero; - public TimeSpan TotalAge => Meta.TouchedAt - Meta.CreatedAt; - - public Timed() { } - protected Timed( Timed original ) : base( original ) { Meta = original.Meta; } - - - public override T Process( - Func fn, - string reason = "", - [CallerMemberName] string dbgMethod = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0, - [CallerArgumentExpression( "fn" )] string dbgExpStr = "" ) - { - var current = (T)this; - var next = fn( current ); - - if( ReferenceEquals( current, next ) ) - return current; - - /* - var newMeta = new Metadata_Timed - { - Version = current.Meta.Version + 1, - Reason = reason, - MemberName = dbgMethod, - FilePath = dbgPath, - LineNumber = dbgLine, - Expression = dbgExpression, - OldObject = current, - CreatedAt = current.Meta.CreatedAt, - TouchedAt = DateTime.UtcNow - }; - */ - - var newMeta = current.Meta with - { - Version = current.Meta.Version + 1, - Reason = reason, - MemberName = dbgMethod, - FilePath = dbgPath, - LineNumber = dbgLine, - Expression = dbgExpStr, - OldObject = current, - TouchedAt = DateTime.UtcNow - }; - - // Testing: Shouldnt need the OnChange - var newVersion = next with { Meta = newMeta }; - newVersion.OnChange( current, newVersion ); - return newVersion; - } - - public new T Record( - string reason = "Recorded", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0 ) - { - return Process( t => t, reason, dbgName, dbgPath, dbgLine ); - } -} - -/* -public static class TimedExt -{ public static T Process( ref T obj, Func fn, @@ -368,11 +32,20 @@ public static class TimedExt [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = 0, - [CallerArgumentExpression( "fn" )] string dbgExpression = "" - ) where T : imm.Timed + [CallerArgumentExpression( "fn" )] string dbgExpression = "" ) + where T : io.Recorded // Catches Recorded and Timed { + // This will call the 'Timed' override if T is Timed, + // or the 'Recorded' override if T is Recorded. obj = obj.Process( fn, reason, dbgName, dbgPath, dbgLine, dbgExpression ); return obj; } + + public static string LogDiff( T cur, T old, [CallerArgumentExpression( "cur" )] string dbgExpCur = "", [CallerArgumentExpression( "old" )] string dbgExpOld = "" ) + { + return $"{dbgExpCur} changed from {old} to {cur}"; + } + + // No specific Process needed for Timed, as it's caught by Recorded + // and its Process override handles the timing. } -*/ \ No newline at end of file diff --git a/imm/List.cs b/imm/List.cs index cc63f13..70dae60 100644 --- a/imm/List.cs +++ b/imm/List.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Runtime.CompilerServices; -namespace imm; +namespace io; /// /// An immutable list implementation that tracks history, metadata, and time. @@ -79,4 +79,4 @@ public record class List : Timed>, IImmutableList // --- Standard Interfaces --- public IEnumerator GetEnumerator() => Values.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)Values).GetEnumerator(); -} \ No newline at end of file +} diff --git a/imm/Util.cs b/imm/Util.cs index d77d58e..585827a 100644 --- a/imm/Util.cs +++ b/imm/Util.cs @@ -1,4 +1,2 @@ using System; using System.Collections.Generic; - -namespace imm; diff --git a/imm/io.cs b/imm/io.cs new file mode 100644 index 0000000..840d319 --- /dev/null +++ b/imm/io.cs @@ -0,0 +1,378 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; + +namespace io; + +/// +/// Represents the base interface for versioned, immutable objects. +/// Provides access to metadata and potentially the previous version. +/// +public interface Obj +{ + /// + /// Gets the base metadata associated with this version. + /// + Metadata_Versioned Meta { get; } + + /// + /// Gets the previous version as a base object, if available. + /// Returns null if this is the first version or if history is not tracked. + /// + Obj? Old { get; } + + /// + /// Creates a new version without functional change. + /// Returns the new version as an Obj. + /// + Obj Record( + string reason = "Recorded", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0 ); +} + + +/// +/// Obj delegate for change notifications. +/// +public delegate void ChangeDelegate( T? oldVersion, T newVersion ); + + +/// +/// Represents a generic interface for immutable objects, +/// providing access to basic processing functions and change notifications. +/// +public interface Obj : Obj where T : Obj +{ + /// + /// Gets the change delegate associated with this object. + /// + [JsonIgnore] + ChangeDelegate OnChange { get; set; } + + /// + /// Applies a transformation and creates a new version using basic processing. + /// + T Process( + Func fn, + string reason = "Processed", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, + [CallerArgumentExpression( "fn" )] string expStr = "" ); + + + /// + /// Creates a new version without a functional change using basic processing. + /// Uses 'new' to provide a type-safe return. + /// + new T Record( + string reason = "Recorded", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0 ); +} + + +/* +static public class ObjExtensions +{ + /// + /// Creates a new version of the object with the specified reason. + /// + public static T Record( this T obj, string reason = "Recorded" ) where T : Obj + { + if( obj is Recorded recorded ) + { + return recorded.Record( reason ); + } + else if( obj is Versioned versioned ) + { + return versioned.Record( reason ); + } + else + { + // Dont care + + return obj; + } + } +} +*/ + +// --- Metadata Hierarchy --- + +public interface VersionedMeta +{ + public uint Version { get; } + public string Reason { get; } +} + + +/// +/// Obj metadata for version tracking. +/// +public record Metadata_Versioned +{ + public uint Version { get; init; } = 1; + public string Reason { get; init; } = "Created"; +} + + +public interface RecordedMeta : VersionedMeta +{ + public string MemberName { get; } + public string FilePath { get; } + public int LineNumber { get; } + public string Expression { get; } +} + + +/// +/// Metadata for version and recording (debug/caller info, history). +/// +public record Metadata_Recorded : Metadata_Versioned, RecordedMeta +{ + internal object? OldObject { get; init; } = null; + public string MemberName { get; init; } = ""; + public string FilePath { get; init; } = ""; + public int LineNumber { get; init; } = 0; + public string Expression { get; init; } = ""; +} + +public interface TimedMeta : RecordedMeta +{ + public DateTime CreatedAt { get; } + public DateTime TouchedAt { get; } +} + + +/// +/// Metadata for version, recording, and timing. +/// +public record Metadata_Timed : Metadata_Recorded, TimedMeta +{ + public DateTime CreatedAt { get; init; } = DateTime.UtcNow; + public DateTime TouchedAt { get; init; } = DateTime.UtcNow; +} + +// --- Record Hierarchy --- + +/// +/// Level 1: Basic versioning. Implements Obj. +/// +public record class Versioned : Obj where T : Versioned +{ + public Metadata_Versioned Meta { get; init; } = new(); + + [DebuggerBrowsable( DebuggerBrowsableState.Never )] + [JsonIgnore] + public ChangeDelegate OnChange { get; set; } = ( o, n ) => { }; + + public virtual Obj? Old => null; + + Metadata_Versioned Obj.Meta => this.Meta; + [JsonIgnore] + Obj? Obj.Old => this.Old; + + public Versioned() { } + protected Versioned( Versioned original ) + { + OnChange = original.OnChange; + Meta = original.Meta; + } + + public virtual T Process( + Func fn, + string reason = "Processed", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, + [CallerArgumentExpression( "fn" )] string expStr = "" ) + { + var current = (T)this; + var next = fn( current ); + + if( ReferenceEquals( current, next ) ) + return current; + + var newVersion = next with + { + Meta = new Metadata_Versioned { /*...*/ }, + OnChange = current.OnChange + }; + newVersion.OnChange( current, newVersion ); + return newVersion; + } + + /// + /// Basic Record. Made virtual. Implements Obj.Record. + /// + public virtual T Record( + string reason = "Recorded", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0 ) => Process( t => t, reason, dbgName, dbgPath, dbgLine ); + + /// + /// Implements Obj.Record by calling the virtual T Record. + /// + Obj Obj.Record( + string reason = "Recorded", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0 ) => this.Record( reason, dbgName, dbgPath, dbgLine ); + + +} + +/// +/// Level 2: Adds history and caller info. +/// +public record class Recorded : Versioned where T : Recorded +{ + new public Metadata_Recorded Meta { get; init; } = new(); + + [JsonIgnore] + new public T? Old => Meta.OldObject as T; + + //public override Obj? Old => this.Old; + //Metadata_Versioned Obj.Meta => this.Meta; + + public Recorded() { } + protected Recorded( Recorded original ) : base( original ) { Meta = original.Meta; } + + public override T Process( + Func fn, + string reason = "", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, + [CallerArgumentExpression( "fn" )] string expStr = "" ) + { + var current = (T)this; + var next = fn( current ); + + if( ReferenceEquals( current, next ) ) + return current; + + var newMeta = current.Meta with { + Version = current.Meta.Version + 1, + Reason = reason, + MemberName = dbgName, + FilePath = dbgPath, + LineNumber = dbgLine, + Expression = expStr, + OldObject = current, + }; + + var newVersion = next with { Meta = newMeta, OnChange = current.OnChange }; + newVersion.OnChange( current, newVersion ); + return newVersion; + } + + public new T Record( + string reason = "Recorded", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0 ) + { + return Process( t => t, reason, dbgName, dbgPath, dbgLine ); + } + +} + +/// +/// Level 3: Adds timestamps. +/// +public record class Timed : Recorded where T : Timed +{ + new public Metadata_Timed Meta { get; init; } = new(); + //Metadata_Versioned Obj.Meta => this.Meta; + public TimeSpan SinceLastTouch => Meta.TouchedAt - ( Old?.Meta as Metadata_Timed )?.TouchedAt ?? TimeSpan.Zero; + public TimeSpan TotalAge => Meta.TouchedAt - Meta.CreatedAt; + + public Timed() { } + protected Timed( Timed original ) : base( original ) { Meta = original.Meta; } + + + public override T Process( + Func fn, + string reason = "", + [CallerMemberName] string dbgMethod = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, + [CallerArgumentExpression( "fn" )] string dbgExpStr = "" ) + { + var current = (T)this; + var next = fn( current ); + + if( ReferenceEquals( current, next ) ) + return current; + + /* + var newMeta = new Metadata_Timed + { + Version = current.Meta.Version + 1, + Reason = reason, + MemberName = dbgMethod, + FilePath = dbgPath, + LineNumber = dbgLine, + Expression = dbgExpression, + OldObject = current, + CreatedAt = current.Meta.CreatedAt, + TouchedAt = DateTime.UtcNow + }; + */ + + var newMeta = current.Meta with + { + Version = current.Meta.Version + 1, + Reason = reason, + MemberName = dbgMethod, + FilePath = dbgPath, + LineNumber = dbgLine, + Expression = dbgExpStr, + OldObject = current, + TouchedAt = DateTime.UtcNow + }; + + // Testing: Shouldnt need the OnChange + var newVersion = next with { Meta = newMeta }; + newVersion.OnChange( current, newVersion ); + return newVersion; + } + + public new T Record( + string reason = "Recorded", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0 ) + { + return Process( t => t, reason, dbgName, dbgPath, dbgLine ); + } +} + +/* +public static class TimedExt +{ + public static T Process( + ref T obj, + Func fn, + string reason = "", + [CallerMemberName] string dbgName = "", + [CallerFilePath] string dbgPath = "", + [CallerLineNumber] int dbgLine = 0, + [CallerArgumentExpression( "fn" )] string dbgExpression = "" + ) where T : io.Timed + { + obj = obj.Process( fn, reason, dbgName, dbgPath, dbgLine, dbgExpression ); + return obj; + } +} +*/ diff --git a/imm/iu.cs b/imm/iu.cs deleted file mode 100644 index 0e8baed..0000000 --- a/imm/iu.cs +++ /dev/null @@ -1,52 +0,0 @@ -//#nullable enable - -using System; -using System.Runtime.CompilerServices; -using imm; - -/// -/// Helper static class for processing immutable objects using a 'ref' pattern. -/// Provides different levels of processing based on the type. -/// -public static class iu -{ - /// - /// Processes a 'Versioned' object (Level 1). - /// - public static T LightProcess( - ref T obj, - Func fn, - string reason = "Processed" ) - where T : Versioned - { - obj = obj.Process( fn, reason ); - return obj; - } - - /// - /// Processes a 'Recorded' object (Level 2), capturing caller info. - /// - public static T Process( - ref T obj, - Func fn, - string reason = "", - [CallerMemberName] string dbgName = "", - [CallerFilePath] string dbgPath = "", - [CallerLineNumber] int dbgLine = 0, - [CallerArgumentExpression( "fn" )] string dbgExpression = "" ) - where T : Recorded // Catches Recorded and Timed - { - // This will call the 'Timed' override if T is Timed, - // or the 'Recorded' override if T is Recorded. - obj = obj.Process( fn, reason, dbgName, dbgPath, dbgLine, dbgExpression ); - return obj; - } - - public static string LogDiff( T cur, T old, [CallerArgumentExpression( "cur" )] string dbgExpCur = "", [CallerArgumentExpression( "old" )] string dbgExpOld = "" ) - { - return $"{dbgExpCur} changed from {old} to {cur}"; - } - - // No specific Process needed for Timed, as it's caught by Recorded - // and its Process override handles the timing. -} \ No newline at end of file diff --git a/lib/CodeGen.cs b/lib/CodeGen.cs index 5931b48..676ea51 100644 --- a/lib/CodeGen.cs +++ b/lib/CodeGen.cs @@ -17,7 +17,7 @@ using System.Collections.Immutable; namespace ser; -public record CodeGenConfig : imm.Recorded +public record CodeGenConfig : io.Recorded { // Whitelists (if needed, otherwise rely on attributes/defaults) public ImmutableDictionary> WLProps { get; init; } = ImmutableDictionary>.Empty; diff --git a/lib/XmlFormatter2.cs b/lib/XmlFormatter2.cs index a60f5a9..715f1be 100644 --- a/lib/XmlFormatter2.cs +++ b/lib/XmlFormatter2.cs @@ -490,7 +490,7 @@ namespace lib { if( _cfg.VerboseLogging ) log.info( $"" ); - var isImm = typeof(imm.Obj).IsAssignableFrom( narrowType ); + var isImm = typeof(io.Obj).IsAssignableFrom( narrowType ); XmlNodeList allChildren = elem.ChildNodes; @@ -648,8 +648,8 @@ namespace lib } else { - var imm = obj as imm.Obj; - var newObj = imm.Record( $"From XML {fromStr}:{elem.ParentNode?.Name}{elem.Name}" ); + var immObj = obj as io.Obj; + var newObj = immObj.Record( $"From XML {fromStr}:{elem.ParentNode?.Name}{elem.Name}" ); return newObj; } @@ -1290,7 +1290,7 @@ namespace lib HashSet whitelistFields, whitelistProps; GetFilters( _cfg.TypesDefault, mi, narrowType, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps ); - var isImm = typeof(imm.Obj).IsAssignableFrom( narrowType ); + var isImm = typeof(io.Obj).IsAssignableFrom( narrowType ); if( doFields || doImpls ) { diff --git a/logging/Log.cs b/logging/Log.cs index 012eb7f..4dc67e9 100644 --- a/logging/Log.cs +++ b/logging/Log.cs @@ -32,6 +32,7 @@ N O T  D O I N G : */ +#region Helpers public record struct Value( T _val, string _exp = "" ) { public static T Default = default!; @@ -87,13 +88,10 @@ public struct SourceLoc } - +#endregion // Helpers static public class log { - - //static - #region CLR Logging @@ -155,14 +153,6 @@ static public class log #endregion // CLR Logging - static public Value Value( T val, - [CallerArgumentExpression("val")] - string dbgExp = "" -) - { - return new( val, dbgExp ); - } - [Flags] public enum LogType { @@ -184,13 +174,15 @@ static public class log { None = 0, - File = 1 << 0, + File = 1 << 0, Console = 1 << 1, All = File | Console, } +#region LogEvent + public struct LogEvent { public DateTime Time; @@ -264,7 +256,7 @@ static public class log ImmutableInterlocked.AddOrUpdate( ref s_logEPforCat, cat, ep, ( k, v ) => ep ); } - +#endregion // LogEvent static public void shutdown() { @@ -1020,4 +1012,13 @@ static public class log private static ArrayList s_delegates = new ArrayList(); -} + static public Value Value( T val, + [CallerArgumentExpression("val")] + string dbgExp = "" +) + { + return new( val, dbgExp ); + } + + +} // end static class log diff --git a/res/Resource.cs b/res/Resource.cs index b9c3a6f..2ceb0c5 100644 --- a/res/Resource.cs +++ b/res/Resource.cs @@ -182,7 +182,7 @@ public class Ref : Ref where T : class, new() // Let's assume you'll add saving logic here. // Mgr.Save(value, path); // Example: Needs implementation - var immMeta = (value as imm.Obj)?.Meta; + var immMeta = (value as io.Obj)?.Meta; @@ -365,7 +365,7 @@ public static class Mgr { return cachedValue; } - + // 2. Get a lock specific to this filename and lock it. var fileLock = s_loadingLocks.GetOrAdd( filename, _ => new object() ); lock( fileLock ) @@ -433,10 +433,10 @@ public static class Mgr var loadedObject = loaderHolder.Load( filename, reason, dbgName, dbgPath, dbgLine ); if( loadedObject is T value ) { - var meta = (value as imm.Obj)?.Meta; + var meta = (value as io.Obj)?.Meta; // If it's an immutable object, record its loading. - if( value is imm.Obj imm ) + if( value is io.Obj imm ) { return (T)imm.Record( $"Loading bcs {reason}", dbgName, dbgPath, dbgLine ); } diff --git a/ser/XmlSer.cs b/ser/XmlSer.cs index 310d0b4..97b2e51 100644 --- a/ser/XmlSer.cs +++ b/ser/XmlSer.cs @@ -90,7 +90,7 @@ public enum BackingFieldNaming { Short, Regular } public enum POD { Attributes, Elements } public record struct TypeProxy( Func fnSer, Func fnDes ); -public record XmlCfg : imm.Recorded +public record XmlCfg : io.Recorded { public bool Verbose { get; init; } = false; public Datastructure Structure { get; init; } = Datastructure.Tree; @@ -254,7 +254,7 @@ public class TypeMetaCache GetFilters( _cfg.TypesDefault, type, out doImpls, out doFields, out doProps ); - var isImm = typeof( imm.Obj ).IsAssignableFrom( type ); + var isImm = typeof( io.Obj ).IsAssignableFrom( type ); var typesAtt = type.GetCustomAttribute( true ); var serTypes = typesAtt?.Types ?? ser.Types.None; diff --git a/ser/XmlSer_Read.cs b/ser/XmlSer_Read.cs index cf9b99f..542ef06 100644 --- a/ser/XmlSer_Read.cs +++ b/ser/XmlSer_Read.cs @@ -179,7 +179,7 @@ public partial class ObjectHandler : ITypeHandler // 3. Post-processing if( obj is ser.I_Serialize iSer ) obj = iSer.OnDeserialize( null ); - if( ti.IsImm && obj is imm.Obj immObj ) + if( ti.IsImm && obj is io.Obj immObj ) return immObj.Record( $"From XML {elem.Name}" ); return obj; diff --git a/ser/XmlSer_Tests.cs b/ser/XmlSer_Tests.cs index 6d39013..da59d15 100644 --- a/ser/XmlSer_Tests.cs +++ b/ser/XmlSer_Tests.cs @@ -9,7 +9,7 @@ using System.Text; namespace ser; -public record class SimpleImmutable( string Name, int Age ) : imm.Timed; +public record class SimpleImmutable( string Name, int Age ) : io.Timed; static public class Test { diff --git a/tests/Tests.cs b/tests/Tests.cs index 95c9455..a4ce20e 100644 --- a/tests/Tests.cs +++ b/tests/Tests.cs @@ -10,7 +10,7 @@ using System.IO; namespace test; -public record class SimpleImmutable( string Name, int Age ) : imm.Timed; +public record class SimpleImmutable( string Name, int Age ) : io.Timed; static public class XmlFormatter2 {