Compare commits

..

No commits in common. "28d8c145b5839af0eab8cc23abbac1c0c275fe07" and "2b5940bef69cfcff2903b827ecfd48662bb57114" have entirely different histories.

10 changed files with 213 additions and 127 deletions

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net9.0;net10.0</TargetFrameworks> <TargetFrameworks>net9.0;net8.0;net10.0</TargetFrameworks>
<RootNamespace>lib</RootNamespace> <RootNamespace>lib</RootNamespace>
<AssemblyVersion>0.0.1.0</AssemblyVersion> <AssemblyVersion>0.0.1.0</AssemblyVersion>
<FileVersion>0.0.1.0</FileVersion> <FileVersion>0.0.1.0</FileVersion>

View File

@ -1,6 +1,7 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace exp; namespace exp;

View File

@ -1,4 +1,4 @@
#nullable enable #nullable enable
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -12,7 +12,7 @@ public abstract record class FsmContextBase<TSelf> : io.Recorded<TSelf>
where TSelf : FsmContextBase<TSelf> where TSelf : FsmContextBase<TSelf>
{ {
// Required for 'with' expressions. // Required for 'with' expressions.
protected FsmContextBase(io.Recorded<TSelf> original) : base(original) { } protected FsmContextBase( io.Recorded<TSelf> original ) : base( original ) { }
protected FsmContextBase() { } protected FsmContextBase() { }
} }
@ -29,7 +29,7 @@ public abstract record class FsmStateBase<TSelf, TCtx> : io.Recorded<TSelf>
/// <summary> /// <summary>
/// Called when entering this state. /// Called when entering this state.
/// </summary> /// </summary>
public virtual (TCtx Context, TSelf State) OnEnter(TCtx context, FsmStateBase<TSelf, TCtx> oldState) public virtual (TCtx Context, TSelf State) OnEnter( TCtx context, FsmStateBase<TSelf, TCtx> oldState )
{ {
return (context, (TSelf)this); return (context, (TSelf)this);
} }
@ -37,13 +37,13 @@ public abstract record class FsmStateBase<TSelf, TCtx> : io.Recorded<TSelf>
/// <summary> /// <summary>
/// Called when exiting this state. /// Called when exiting this state.
/// </summary> /// </summary>
public virtual (TCtx Context, TSelf State) OnExit(TCtx context, FsmStateBase<TSelf, TCtx> newState) public virtual (TCtx Context, TSelf State) OnExit( TCtx context, FsmStateBase<TSelf, TCtx> newState )
{ {
return (context, (TSelf)this); return (context, (TSelf)this);
} }
// Required for 'with' expressions. // Required for 'with' expressions.
protected FsmStateBase(io.Recorded<TSelf> original) : base(original) { } protected FsmStateBase( io.Recorded<TSelf> original ) : base( original ) { }
protected FsmStateBase() { } protected FsmStateBase() { }
} }
@ -62,14 +62,14 @@ public abstract record class FsmBase<TSelf, TState, TCtx> : io.Recorded<TSelf>
public TCtx Context { get; init; } public TCtx Context { get; init; }
public TState State { get; init; } public TState State { get; init; }
protected FsmBase(TCtx initialContext, TState initialState) protected FsmBase( TCtx initialContext, TState initialState )
{ {
Context = initialContext; Context = initialContext;
State = initialState; State = initialState;
} }
// Required for 'with' expressions. // Required for 'with' expressions.
protected FsmBase(io.Recorded<TSelf> original) : base(original) protected FsmBase( io.Recorded<TSelf> original ) : base( original )
{ {
var o = original as FsmBase<TSelf, TState, TCtx>; var o = original as FsmBase<TSelf, TState, TCtx>;
Context = o!.Context; Context = o!.Context;
@ -78,7 +78,7 @@ public abstract record class FsmBase<TSelf, TState, TCtx> : io.Recorded<TSelf>
/// <summary> /// <summary>
/// Transitions the FSM. It automatically uses the 'Process' /// Transitions the FSM. It automatically uses the 'Process'
/// method appropriate for io.Recorded or Timed, thanks to virtual overrides. /// method appropriate for io.ecorded or Timed, thanks to virtual overrides.
/// </summary> /// </summary>
public TSelf Transition( public TSelf Transition(
TState newState, TState newState,
@ -86,12 +86,12 @@ public abstract record class FsmBase<TSelf, TState, TCtx> : io.Recorded<TSelf>
[CallerMemberName] string memberName = "", [CallerMemberName] string memberName = "",
[CallerFilePath] string filePath = "", [CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0, [CallerLineNumber] int lineNumber = 0,
[CallerArgumentExpression("newState")] string expression = "") [CallerArgumentExpression( "newState" )] string expression = "" )
{ {
Console.WriteLine($"[FSM] Transition: {State.GetType().Name} -> {newState.GetType().Name}. Reason: {reason}"); Console.WriteLine( $"[FSM] Transition: {State.GetType().Name} -> {newState.GetType().Name}. Reason: {reason}" );
var (ctxAfterExit, stateAfterExit) = State.OnExit(Context, newState); var (ctxAfterExit, stateAfterExit) = State.OnExit( Context, newState );
var (ctxAfterEnter, stateAfterEnter) = newState.OnEnter(ctxAfterExit, stateAfterExit); var (ctxAfterEnter, stateAfterEnter) = newState.OnEnter( ctxAfterExit, stateAfterExit );
// Since 'this' is at least 'io.Recorded<TSelf>', we can call the // Since 'this' is at least 'io.Recorded<TSelf>', we can call the
// detailed 'Process'. If 'this' is actually 'Timed<TSelf>', C#'s // detailed 'Process'. If 'this' is actually 'Timed<TSelf>', C#'s

View File

@ -1,8 +1,9 @@
//#nullable enable //#nullable enable
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
/// <summary> /// <summary>
/// Helper static class for processing immutable objects using a 'ref' pattern. /// Helper static class for processing immutable objects using a 'ref' pattern.
/// Provides different levels of processing based on the type. /// Provides different levels of processing based on the type.
@ -15,8 +16,8 @@ public static class imm
public static T LightProcess<T>( public static T LightProcess<T>(
ref T obj, ref T obj,
Func<T, T> fn, Func<T, T> fn,
string reason = "Processed" ) string reason = "Processed" // TODO Replace the string with a $"" that cinludes some info
where T : io.Versioned<T> ) where T : io.Versioned<T>
{ {
obj = obj.Process( fn, reason ); obj = obj.Process( fn, reason );
return obj; return obj;
@ -42,9 +43,9 @@ public static class imm
} }
public static string LogDiff<T>( T cur, T old, [CallerArgumentExpression( "cur" )] string dbgExpCur = "", [CallerArgumentExpression( "old" )] string dbgExpOld = "" ) public static string LogDiff<T>( T cur, T old, [CallerArgumentExpression( "cur" )] string dbgExpCur = "", [CallerArgumentExpression( "old" )] string dbgExpOld = "" )
{ {
return $"{dbgExpCur} changed from {old} to {cur}"; return $"{dbgExpCur} changed from {old} to {cur}";
} }
// No specific Process needed for Timed, as it's caught by Recorded<T> // No specific Process needed for Timed, as it's caught by Recorded<T>
// and its Process override handles the timing. // and its Process override handles the timing.

View File

@ -11,7 +11,7 @@ namespace io;
/// <summary> /// <summary>
/// An immutable list implementation that tracks history, metadata, and time. /// An immutable list implementation that tracks history, metadata, and time.
/// </summary> /// </summary>
public record class List<T> : Timed<List<T>>, IImmutableList<T> public record class List<T> : io.Timed<List<T>>, IImmutableList<T>
{ {
static public List<T> Empty { get; } = new(); static public List<T> Empty { get; } = new();
@ -19,7 +19,7 @@ public record class List<T> : Timed<List<T>>, IImmutableList<T>
public List() { } public List() { }
// Required for 'with' expressions to work with the base class hierarchy // Required for 'with' expressions to work with the base class hierarchy
protected List(Timed<List<T>> original) : base(original) { } protected List( io.Timed<List<T>> original ) : base( original ) { }
// Helper to apply changes using the Process method // Helper to apply changes using the Process method
private List<T> Change( private List<T> Change(
@ -29,54 +29,54 @@ public record class List<T> : Timed<List<T>>, IImmutableList<T>
[CallerLineNumber] int dbgLine = -1, [CallerLineNumber] int dbgLine = -1,
[CallerArgumentExpression( "listChange" )] string reason = "" ) [CallerArgumentExpression( "listChange" )] string reason = "" )
{ {
var newValues = listChange(Values); var newValues = listChange( Values );
return ReferenceEquals(Values, newValues) return ReferenceEquals( Values, newValues )
? this ? this
: Process(l => l with { Values = newValues }, reason, dbgMethod, dbgPath, dbgLine, reason); : Process( l => l with { Values = newValues }, reason, dbgMethod, dbgPath, dbgLine, reason );
} }
// --- IImmutableList<T> implementation using the Change helper --- // --- IImmutableList<T> implementation using the Change helper ---
public T this[int index] => Values[index]; public T this[int index] => Values[index];
public int Count => Values.Count; public int Count => Values.Count;
public List<T> Add(T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.Add(value), dbgMethod, dbgPath, dbgLine); public List<T> Add( T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Add( value ), dbgMethod, dbgPath, dbgLine );
public List<T> AddRange(IEnumerable<T> items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.AddRange(items), dbgMethod, dbgPath, dbgLine); public List<T> AddRange( IEnumerable<T> items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.AddRange( items ), dbgMethod, dbgPath, dbgLine );
public List<T> Clear([CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.Clear(), dbgMethod, dbgPath, dbgLine); public List<T> Clear( [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Clear(), dbgMethod, dbgPath, dbgLine );
#region IImmutableList Implementati, dbgMethod, dbgPath, dbgLineon #region IImmutableList Implementati, dbgMethod, dbgPath, dbgLineon
public List<T> Insert( int index, T element, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Insert( index, element ) , dbgMethod, dbgPath, dbgLine); public List<T> Insert( int index, T element, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Insert( index, element ), dbgMethod, dbgPath, dbgLine );
public List<T> InsertRange( int index, IEnumerable<T> items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.InsertRange( index, items ) , dbgMethod, dbgPath, dbgLine); public List<T> InsertRange( int index, IEnumerable<T> items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.InsertRange( index, items ), dbgMethod, dbgPath, dbgLine );
public List<T> Remove( T value, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Remove( value, equalityComparer ) , dbgMethod, dbgPath, dbgLine); public List<T> Remove( T value, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Remove( value, equalityComparer ), dbgMethod, dbgPath, dbgLine );
public List<T> Remove( T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Remove( value, EqualityComparer<T>.Default , dbgMethod, dbgPath, dbgLine); public List<T> Remove( T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Remove( value, EqualityComparer<T>.Default, dbgMethod, dbgPath, dbgLine );
public List<T> RemoveAll( Predicate<T> match, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAll( match ) , dbgMethod, dbgPath, dbgLine); public List<T> RemoveAll( Predicate<T> match, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAll( match ), dbgMethod, dbgPath, dbgLine );
public List<T> RemoveAt( int index, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAt( index ) , dbgMethod, dbgPath, dbgLine); public List<T> RemoveAt( int index, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAt( index ), dbgMethod, dbgPath, dbgLine );
public List<T> RemoveRange( int index, int count, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( index, count ) , dbgMethod, dbgPath, dbgLine); public List<T> RemoveRange( int index, int count, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( index, count ), dbgMethod, dbgPath, dbgLine );
public List<T> RemoveRange( IEnumerable<T> items, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( items, equalityComparer ) , dbgMethod, dbgPath, dbgLine); public List<T> RemoveRange( IEnumerable<T> items, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( items, equalityComparer ), dbgMethod, dbgPath, dbgLine );
public List<T> Replace( T oldValue, T newValue, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Replace( oldValue, newValue, equalityComparer ) , dbgMethod, dbgPath, dbgLine); public List<T> Replace( T oldValue, T newValue, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Replace( oldValue, newValue, equalityComparer ), dbgMethod, dbgPath, dbgLine );
public List<T> SetItem( int index, T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.SetItem( index, value ) , dbgMethod, dbgPath, dbgLine); public List<T> SetItem( int index, T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.SetItem( index, value ), dbgMethod, dbgPath, dbgLine );
public int IndexOf( T item, int index, int count, IEqualityComparer<T>? equalityComparer ) => Values.IndexOf( item, index, count, equalityComparer ?? EqualityComparer<T>.Default ); public int IndexOf( T item, int index, int count, IEqualityComparer<T>? equalityComparer ) => Values.IndexOf( item, index, count, equalityComparer ?? EqualityComparer<T>.Default );
public int LastIndexOf( T item, int index, int count, IEqualityComparer<T>? equalityComparer) => Values.LastIndexOf( item, index, count, equalityComparer ?? EqualityComparer<T>.Default ); public int LastIndexOf( T item, int index, int count, IEqualityComparer<T>? equalityComparer ) => Values.LastIndexOf( item, index, count, equalityComparer ?? EqualityComparer<T>.Default );
public int IndexOf( T item, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => IndexOf( item, 0, Count, EqualityComparer<T>.Default); public int IndexOf( T item, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => IndexOf( item, 0, Count, EqualityComparer<T>.Default );
IImmutableList<T> IImmutableList<T>.Clear() => Clear(); IImmutableList<T> IImmutableList<T>.Clear() => Clear();
IImmutableList<T> IImmutableList<T>.Add( T value ) => Add( value ); IImmutableList<T> IImmutableList<T>.Add( T value ) => Add( value );
IImmutableList<T> IImmutableList<T>.AddRange( IEnumerable<T> items ) => AddRange( items ); IImmutableList<T> IImmutableList<T>.AddRange( IEnumerable<T> items ) => AddRange( items );
IImmutableList<T> IImmutableList<T>.Insert( int index, T element ) => Insert( index, element ); IImmutableList<T> IImmutableList<T>.Insert( int index, T element ) => Insert( index, element );
IImmutableList<T> IImmutableList<T>.InsertRange( int index, IEnumerable<T> items ) => InsertRange( index, items ); IImmutableList<T> IImmutableList<T>.InsertRange( int index, IEnumerable<T> items ) => InsertRange( index, items );
IImmutableList<T> IImmutableList<T>.Remove( T value, IEqualityComparer<T>? equalityComparer ) => Remove( value, equalityComparer ); IImmutableList<T> IImmutableList<T>.Remove( T value, IEqualityComparer<T>? equalityComparer ) => Remove( value, equalityComparer );
IImmutableList<T> IImmutableList<T>.RemoveAll( Predicate<T> match ) => RemoveAll( match ); IImmutableList<T> IImmutableList<T>.RemoveAll( Predicate<T> match ) => RemoveAll( match );
IImmutableList<T> IImmutableList<T>.RemoveAt( int index ) => RemoveAt( index ); IImmutableList<T> IImmutableList<T>.RemoveAt( int index ) => RemoveAt( index );
IImmutableList<T> IImmutableList<T>.RemoveRange( IEnumerable<T> items, IEqualityComparer<T>? equalityComparer ) => RemoveRange( items, equalityComparer ); IImmutableList<T> IImmutableList<T>.RemoveRange( IEnumerable<T> items, IEqualityComparer<T>? equalityComparer ) => RemoveRange( items, equalityComparer );
IImmutableList<T> IImmutableList<T>.RemoveRange( int index, int count ) => RemoveRange( index, count ); IImmutableList<T> IImmutableList<T>.RemoveRange( int index, int count ) => RemoveRange( index, count );
IImmutableList<T> IImmutableList<T>.Replace( T oldValue, T newValue, IEqualityComparer<T>? equalityComparer ) => Replace( oldValue, newValue, equalityComparer ); IImmutableList<T> IImmutableList<T>.Replace( T oldValue, T newValue, IEqualityComparer<T>? equalityComparer ) => Replace( oldValue, newValue, equalityComparer );
IImmutableList<T> IImmutableList<T>.SetItem( int index, T value ) => SetItem( index, value ); IImmutableList<T> IImmutableList<T>.SetItem( int index, T value ) => SetItem( index, value );
#endregion #endregion
// --- Standard Interfaces --- // --- Standard Interfaces ---
public IEnumerator<T> GetEnumerator() => Values.GetEnumerator(); public IEnumerator<T> GetEnumerator() => Values.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)Values).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => ( (IEnumerable)Values ).GetEnumerator();
} }

View File

@ -1,2 +1,3 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -23,7 +23,7 @@ public interface Obj
/// Gets the previous version as a base object, if available. /// Gets the previous version as a base object, if available.
/// Returns null if this is the first version or if history is not tracked. /// Returns null if this is the first version or if history is not tracked.
/// </summary> /// </summary>
Obj? Old { get; } Obj? DebugOld { get; }
/// <summary> /// <summary>
/// Creates a new version without functional change. /// Creates a new version without functional change.
@ -174,11 +174,11 @@ public record class Versioned<T> : Obj<T> where T : Versioned<T>
[JsonIgnore] [JsonIgnore]
public ChangeDelegate<T> OnChange { get; set; } = ( o, n ) => { }; public ChangeDelegate<T> OnChange { get; set; } = ( o, n ) => { };
public virtual Obj? Old => null; public virtual Obj? DebugOld => null;
Metadata_Versioned Obj.Meta => this.Meta; Metadata_Versioned Obj.Meta => this.Meta;
[JsonIgnore] [JsonIgnore]
Obj? Obj.Old => this.Old; Obj? Obj.DebugOld => this.DebugOld;
public Versioned() { } public Versioned() { }
protected Versioned( Versioned<T> original ) protected Versioned( Versioned<T> original )
@ -239,9 +239,9 @@ public record class Recorded<T> : Versioned<T> where T : Recorded<T>
new public Metadata_Recorded Meta { get; init; } = new(); new public Metadata_Recorded Meta { get; init; } = new();
[JsonIgnore] [JsonIgnore]
new public T? Old => Meta.OldObject as T; new public T? DebugOld => Meta.OldObject as T;
//public override Obj? Old => this.Old; //public override Obj? DebugOld => this.DebugOld;
//Metadata_Versioned Obj.Meta => this.Meta; //Metadata_Versioned Obj.Meta => this.Meta;
public Recorded() { } public Recorded() { }
@ -261,7 +261,8 @@ public record class Recorded<T> : Versioned<T> where T : Recorded<T>
if( ReferenceEquals( current, next ) ) if( ReferenceEquals( current, next ) )
return current; return current;
var newMeta = current.Meta with { var newMeta = current.Meta with
{
Version = current.Meta.Version + 1, Version = current.Meta.Version + 1,
Reason = reason, Reason = reason,
MemberName = dbgName, MemberName = dbgName,
@ -294,7 +295,7 @@ public record class Timed<T> : Recorded<T> where T : Timed<T>
{ {
new public Metadata_Timed Meta { get; init; } = new(); new public Metadata_Timed Meta { get; init; } = new();
//Metadata_Versioned Obj.Meta => this.Meta; //Metadata_Versioned Obj.Meta => this.Meta;
public TimeSpan SinceLastTouch => Meta.TouchedAt - ( Old?.Meta as Metadata_Timed )?.TouchedAt ?? TimeSpan.Zero; public TimeSpan SinceLastTouch => Meta.TouchedAt - ( DebugOld?.Meta as Metadata_Timed )?.TouchedAt ?? TimeSpan.Zero;
public TimeSpan TotalAge => Meta.TouchedAt - Meta.CreatedAt; public TimeSpan TotalAge => Meta.TouchedAt - Meta.CreatedAt;
public Timed() { } public Timed() { }

View File

@ -139,7 +139,7 @@ namespace lib
private string fromStr = ""; private string fromStr = "";
void SetFromStr( Stream stream ) void SetFromStr( Stream stream )
{ {
fromStr = stream.ToString() ?? "{null}"; fromStr = stream.ToString() ?? "{null}";
@ -186,7 +186,8 @@ namespace lib
doc.Load( reader ); doc.Load( reader );
if( doc.DocumentElement == null ) return null; if( doc.DocumentElement == null )
return null;
if( t == null ) if( t == null )
return Deserialize( doc.DocumentElement ); return Deserialize( doc.DocumentElement );
@ -256,7 +257,8 @@ namespace lib
{ {
TypeCode typeCode = Type.GetTypeCode( type ); TypeCode typeCode = Type.GetTypeCode( type );
if( _cfg.VerboseLogging ) log.info( $"{type.FriendlyName()}.{name} {existing} {mi?.Name}" ); if( _cfg.VerboseLogging )
log.info( $"{type.FriendlyName()}.{name} {existing} {mi?.Name}" );
if( typeCode != TypeCode.Object ) if( typeCode != TypeCode.Object )
{ {
@ -276,7 +278,8 @@ namespace lib
if( obj is ser.I_Serialize iser ) if( obj is ser.I_Serialize iser )
{ {
if( _cfg.VerboseLogging ) log.info( $"" ); if( _cfg.VerboseLogging )
log.info( $"" );
obj = iser.OnDeserialize( null ); obj = iser.OnDeserialize( null );
} }
@ -314,7 +317,8 @@ namespace lib
private object DeserializeConcrete( XmlElement elem, MemberInfo mi, string name, Type type ) private object DeserializeConcrete( XmlElement elem, MemberInfo mi, string name, Type type )
{ {
if( _cfg.VerboseLogging ) log.info( $"" ); if( _cfg.VerboseLogging )
log.info( $"" );
string val = ""; string val = "";
@ -398,7 +402,8 @@ namespace lib
private object HydrateObject( XmlElement elem, MemberInfo mi, Type finalType, object obj ) private object HydrateObject( XmlElement elem, MemberInfo mi, Type finalType, object obj )
{ {
if( _cfg.VerboseLogging ) log.info( $"" ); if( _cfg.VerboseLogging )
log.info( $"" );
if( obj is IList ) if( obj is IList )
{ {
@ -488,9 +493,10 @@ namespace lib
private object HydrateObjectOfNarrowType( XmlElement elem, MemberInfo mi, Type narrowType, object obj ) private object HydrateObjectOfNarrowType( XmlElement elem, MemberInfo mi, Type narrowType, object obj )
{ {
if( _cfg.VerboseLogging ) log.info( $"" ); if( _cfg.VerboseLogging )
log.info( $"" );
var isImm = typeof(io.Obj).IsAssignableFrom( narrowType ); var isImm = typeof( io.Obj ).IsAssignableFrom( narrowType );
XmlNodeList allChildren = elem.ChildNodes; XmlNodeList allChildren = elem.ChildNodes;
@ -536,7 +542,7 @@ namespace lib
name = refl.TypeToIdentifier( name ); name = refl.TypeToIdentifier( name );
// @@@ TODO This doesnt yet handle propNames! // @@@ TODO This doesnt yet handle propNames!
if( !doAtt.Any() && FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) ) if( !doAtt.Any() && FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) )
continue; continue;
var useFieldName = true; var useFieldName = true;
@ -625,7 +631,7 @@ namespace lib
{ {
object existingObj = childPi.GetValue( obj ); object existingObj = childPi.GetValue( obj );
object childObj = DeserializeConcrete( elem, childPi, name, childPi.PropertyType ); object childObj = DeserializeConcrete( elem, childPi, name, childPi.PropertyType );
if( setMethod != null ) if( setMethod != null )
{ {
@ -642,14 +648,14 @@ namespace lib
} }
} }
if(!isImm) if( !isImm )
{ {
return obj; return obj;
} }
else else
{ {
var immObj = obj as io.Obj; var imm = obj as io.Obj;
var newObj = immObj.Record( $"From XML {fromStr}:{elem.ParentNode?.Name}{elem.Name}" ); var newObj = imm.Record( $"From XML {fromStr}:{elem.ParentNode?.Name}{elem.Name}" );
return newObj; return newObj;
} }
@ -686,7 +692,8 @@ namespace lib
int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1; int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1;
if( _cfg.VerboseLogging ) log.info( $"{finalType?.FriendlyName()}({type?.FriendlyName()}) refInt {refInt} exitingObj = {obj?.ToString()}" ); if( _cfg.VerboseLogging )
log.info( $"{finalType?.FriendlyName()}({type?.FriendlyName()}) refInt {refInt} exitingObj = {obj?.ToString()}" );
obj = createObject( elem, finalType, refInt, obj ); obj = createObject( elem, finalType, refInt, obj );
@ -695,7 +702,8 @@ namespace lib
private object DeserializeList( XmlElement elem, MemberInfo mi, Type type, IList list ) private object DeserializeList( XmlElement elem, MemberInfo mi, Type type, IList list )
{ {
if( _cfg.VerboseLogging ) log.info( $"" ); if( _cfg.VerboseLogging )
log.info( $"" );
XmlNodeList arrNodeList = elem.ChildNodes; XmlNodeList arrNodeList = elem.ChildNodes;
@ -731,7 +739,8 @@ namespace lib
typeElem = typeof( KeyValuePair<,> ).MakeGenericType( type.GenericTypeArguments ); typeElem = typeof( KeyValuePair<,> ).MakeGenericType( type.GenericTypeArguments );
} }
if( _cfg.VerboseLogging ) log.info( $"DserCol {type.GetType().FriendlyName()} {typeElem.Name} into reflT {mi.ReflectedType.FriendlyName()} declT {mi.DeclaringType.FriendlyName()} {mi.Name}" ); if( _cfg.VerboseLogging )
log.info( $"DserCol {type.GetType().FriendlyName()} {typeElem.Name} into reflT {mi.ReflectedType.FriendlyName()} declT {mi.DeclaringType.FriendlyName()} {mi.Name}" );
string refString = elem.GetAttribute( "ref" ); string refString = elem.GetAttribute( "ref" );
int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1; int refInt = refString.Length > 0 ? Convert.ToInt32( refString ) : -1;
@ -776,7 +785,8 @@ namespace lib
var typeGen = Type.MakeGenericSignatureType( type ); var typeGen = Type.MakeGenericSignatureType( type );
if( _cfg.VerboseLogging ) log.info( $"TypeGen: {typeGen.FriendlyName()}" ); if( _cfg.VerboseLogging )
log.info( $"TypeGen: {typeGen.FriendlyName()}" );
if( type == typeof( ImmutableArray<> ).MakeGenericType( typeElem ) ) if( type == typeof( ImmutableArray<> ).MakeGenericType( typeElem ) )
{ {
@ -833,7 +843,8 @@ namespace lib
private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type ) private object DeserializeArray( XmlElement elem, MemberInfo mi, Type type )
{ {
if( _cfg.VerboseLogging ) log.info( $"" ); if( _cfg.VerboseLogging )
log.info( $"" );
Type typeElem = type.GetElementType(); Type typeElem = type.GetElementType();
@ -883,7 +894,8 @@ namespace lib
if( _cfg.datastructure == Datastructure.Graph && refInt > 0 && m_alreadySerialized.ContainsKey( refInt ) ) if( _cfg.datastructure == Datastructure.Graph && refInt > 0 && m_alreadySerialized.ContainsKey( refInt ) )
{ {
if( _cfg.VerboseLogging ) log.info( $"Reuse object" ); if( _cfg.VerboseLogging )
log.info( $"Reuse object" );
return m_alreadySerialized[refInt]; return m_alreadySerialized[refInt];
} }
@ -893,7 +905,8 @@ namespace lib
if( isProxy ) if( isProxy )
{ {
if( _cfg.VerboseLogging ) log.info( $"use Proxy" ); if( _cfg.VerboseLogging )
log.info( $"use Proxy" );
object obj = null; object obj = null;
var tryType = type; var tryType = type;
@ -937,7 +950,8 @@ namespace lib
if( isSubclass ) if( isSubclass )
{ {
if( _cfg.VerboseLogging ) log.info( $"Using existing obj {existingObj?.ToString()}" ); if( _cfg.VerboseLogging )
log.info( $"Using existing obj {existingObj?.ToString()}" );
return existingObj; return existingObj;
} }
@ -953,12 +967,14 @@ namespace lib
try try
{ {
if( _cfg.VerboseLogging ) log.info( $"For {type.FriendlyName()} check for constructors" ); if( _cfg.VerboseLogging )
log.info( $"For {type.FriendlyName()} check for constructors" );
var cons = type.GetConstructor( Type.EmptyTypes ); var cons = type.GetConstructor( Type.EmptyTypes );
if( cons != null) if( cons != null )
{ {
if( _cfg.VerboseLogging ) log.info( $"Activator.CreateInstance" ); if( _cfg.VerboseLogging )
log.info( $"Activator.CreateInstance" );
obj = Activator.CreateInstance( type ); obj = Activator.CreateInstance( type );
} }
else else
@ -967,15 +983,18 @@ namespace lib
obj = System.Runtime.Serialization.FormatterServices.GetUninitializedObject( type ); obj = System.Runtime.Serialization.FormatterServices.GetUninitializedObject( type );
} }
if( _cfg.VerboseLogging ) log.info( $"Got obj {obj?.ToString()}" ); if( _cfg.VerboseLogging )
log.info( $"Got obj {obj?.ToString()}" );
} }
catch( Exception ) catch( Exception )
{ {
try try
{ {
if( _cfg.VerboseLogging ) log.info( $"GetUninitializedObject" ); if( _cfg.VerboseLogging )
log.info( $"GetUninitializedObject" );
obj = System.Runtime.Serialization.FormatterServices.GetUninitializedObject( type ); obj = System.Runtime.Serialization.FormatterServices.GetUninitializedObject( type );
if( _cfg.VerboseLogging ) log.info( $"Got obj {obj?.ToString()}" ); if( _cfg.VerboseLogging )
log.info( $"Got obj {obj?.ToString()}" );
} }
catch( Exception exInner ) catch( Exception exInner )
{ {
@ -1290,7 +1309,7 @@ namespace lib
HashSet<string> whitelistFields, whitelistProps; HashSet<string> whitelistFields, whitelistProps;
GetFilters( _cfg.TypesDefault, mi, narrowType, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps ); GetFilters( _cfg.TypesDefault, mi, narrowType, out filterFields, out filterProps, out doImpls, out doFields, out doProps, out whitelistFields, out whitelistProps );
var isImm = typeof(io.Obj).IsAssignableFrom( narrowType ); var isImm = typeof( io.Obj ).IsAssignableFrom( narrowType );
if( doFields || doImpls ) if( doFields || doImpls )
{ {
@ -1323,8 +1342,10 @@ namespace lib
if( isImm ) if( isImm )
{ {
if( name == "MetaStorage" ) continue; if( name == "MetaStorage" )
if( name == "Fn" ) continue; continue;
if( name == "Fn" )
continue;
} }
if( !doAtt.Any() && FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) ) if( !doAtt.Any() && FilterField( filterFields, doImpls, whitelistFields, childFi as MemberInfo, name ) )
@ -1365,8 +1386,10 @@ namespace lib
if( isImm ) if( isImm )
{ {
if( name == "MetaStorage" ) continue; if( name == "MetaStorage" )
if( name == "Fn" ) continue; continue;
if( name == "Fn" )
continue;
} }
if( FilterField( filterProps, doImpls, whitelistProps, childPi as MemberInfo, name ) ) if( FilterField( filterProps, doImpls, whitelistProps, childPi as MemberInfo, name ) )
@ -1393,15 +1416,15 @@ namespace lib
var custWLProps = mi?.GetCustomAttribute<ser.ChildPropsAttribute>( true ); var custWLProps = mi?.GetCustomAttribute<ser.ChildPropsAttribute>( true );
filterFields = custWLFields != null; filterFields = custWLFields != null;
filterProps = custWLProps != null; filterProps = custWLProps != null;
var typesTodo = type.GetCustomAttribute<ser.Ser>( true )?.Types ?? TypesDefault; var typesTodo = type.GetCustomAttribute<ser.Ser>( true )?.Types ?? TypesDefault;
doImpls = typesTodo.HasFlag( ser.Types.Implied ); doImpls = typesTodo.HasFlag( ser.Types.Implied );
doFields = filterFields || typesTodo.HasFlag( ser.Types.Fields ); doFields = filterFields || typesTodo.HasFlag( ser.Types.Fields );
doProps = filterProps || typesTodo.HasFlag( ser.Types.Props ); doProps = filterProps || typesTodo.HasFlag( ser.Types.Props );
whitelistFields = new( custWLFields?.Values ?? new string[0] ); whitelistFields = new( custWLFields?.Values ?? new string[0] );
whitelistProps = new( custWLProps?.Values ?? new string[0] ); whitelistProps = new( custWLProps?.Values ?? new string[0] );
} }
private void SerializeArray( XmlWriter writer, MemberInfo mi, Type mType, object root, int depth ) private void SerializeArray( XmlWriter writer, MemberInfo mi, Type mType, object root, int depth )
@ -1413,8 +1436,10 @@ namespace lib
Type type = root.GetType(); Type type = root.GetType();
Type typeOfMember = typeof( object ); Type typeOfMember = typeof( object );
if( mi is FieldInfo fi ) typeOfMember = fi.FieldType; if( mi is FieldInfo fi )
if( mi is PropertyInfo pi ) typeOfMember = pi.PropertyType; typeOfMember = fi.FieldType;
if( mi is PropertyInfo pi )
typeOfMember = pi.PropertyType;
if( typeOfMember != type ) if( typeOfMember != type )
{ {
log.info( $"SerArr {typeOfMember.FriendlyName()} {mi?.Name} != {type.FriendlyName()}" ); log.info( $"SerArr {typeOfMember.FriendlyName()} {mi?.Name} != {type.FriendlyName()}" );

View File

@ -18,10 +18,10 @@ using System.Text;
/* /*
T O D O : T O D O :
x) Hook the C# prints from glue.
x) Fix
x) Refactor various logs in order to do automagic structured logging x) Refactor various logs in order to do automagic structured logging
ref: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler ref: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler
x) Add support for structured logging (e.g., JSON, XML)
x) Implement a centralized logger that can be used across the application
D O N E: D O N E:
@ -32,7 +32,63 @@ N O T  D O I N G :
*/ */
#region Helpers
/*
// L L M
# Context: Logging Infrastructure (`log` static class)
**Strict Rule:** DO NOT use `Console.WriteLine`, `Debug.WriteLine`, or standard `ILogger`. Use the static `log` class for all diagnostics.
## Core Design Pattern
The logging system uses **Caller Info Attributes** (`[CallerMemberName]`, `[CallerFilePath]`, etc.) to automatically capture context. Do not manually format method names or file paths in messages.
## API Surface
### 1. Standard Levels. Standard goto loggin
* `log.trace(msg)`, `log.debug(msg)`, `log.info(msg)`
* `log.warn(msg)`, `log.high(msg)`
* `log.error(msg)`, `log.fatal(msg)`
* **Signature:** `(string msg, string cat = "", SourceLoc? loc = null)`
* *Note:* `cat` (Category) and `loc` (SourceLocation) are optional; the system auto-resolves `cat` based on directory structure if omitted.
### 2. Functional Pass-Throughs If necessary
Use these to log data flow without breaking the statement chain.
* `T log.var<T>(T val)`: Logs `name_of_var = value` and returns `val`.
* `T log.call<T>(Func<T> func)`: Logs entry, executes `func`, logs exit + result, returns result.
* `void log.call(Action func)`: Logs entry, executes `action`, logs exit.
* `log.operations(Action/Func)`: Wraps execution with info logs.
### 3. Special Types
* `Value<T>`: A struct wrapper to capture variable expressions alongside values. Use `log.Value(var)` when you need explicit expression capturing in custom constructs.
* `log.exception(Exception ex, string msg)`: specialized dump for exceptions.
* `log.logProps(object obj, string header)`: Reflection-based dump of all properties on an object.
## Idiomatic Usage Examples
**Good:**
```csharp
// Variable inspection (Pass-through)
int x = log.var(Calculate());
// Function tracing
var result = log.call(() => ComplexCalculation(input));
// Exception handling
try { ... }
catch (Exception ex) { log.exception(ex, "Calculation failed"); }
// Object Dump
log.logProps(userConfig, "Current Config State");
```
**Bad:**
```csharp
int x = Calculate();
Console.WriteLine("x is " + x); // Forbidden
log.info($"x = {x}"); // Redundant manual formatting
```
*/
public record struct Value<T>( T _val, string _exp = "" ) public record struct Value<T>( T _val, string _exp = "" )
{ {
public static T Default = default!; public static T Default = default!;
@ -88,10 +144,13 @@ public struct SourceLoc
} }
#endregion // Helpers
static public class log static public class log
{ {
//static
#region CLR Logging #region CLR Logging
@ -153,6 +212,14 @@ static public class log
#endregion // CLR Logging #endregion // CLR Logging
static public Value<T> Value<T>( T val,
[CallerArgumentExpression("val")]
string dbgExp = ""
)
{
return new( val, dbgExp );
}
[Flags] [Flags]
public enum LogType public enum LogType
{ {
@ -174,15 +241,13 @@ static public class log
{ {
None = 0, None = 0,
File = 1 << 0, File = 1 << 0,
Console = 1 << 1, Console = 1 << 1,
All = File | Console, All = File | Console,
} }
#region LogEvent
#region LogEvent
public struct LogEvent public struct LogEvent
{ {
public DateTime Time; public DateTime Time;
@ -246,6 +311,7 @@ static public class log
return logEvent; return logEvent;
} }
#endregion // LogEvent
public delegate void Log_delegate( LogEvent evt ); public delegate void Log_delegate( LogEvent evt );
@ -256,7 +322,7 @@ static public class log
ImmutableInterlocked.AddOrUpdate( ref s_logEPforCat, cat, ep, ( k, v ) => ep ); ImmutableInterlocked.AddOrUpdate( ref s_logEPforCat, cat, ep, ( k, v ) => ep );
} }
#endregion // LogEvent
static public void shutdown() static public void shutdown()
{ {
@ -299,7 +365,7 @@ static public class log
pathPieces = path.Split( '/' ); pathPieces = path.Split( '/' );
} }
var lastPathPiece = pathPieces[pathPieces.Length - 1]; var lastPathPiece = pathPieces[pathPieces.Length - 1];
ImmutableInterlocked.AddOrUpdate( ref s_files, pathHash, lastPathPiece, ( key, value ) => { return lastPathPiece; } ); ImmutableInterlocked.AddOrUpdate( ref s_files, pathHash, lastPathPiece, ( key, value ) => { return lastPathPiece; } );
@ -396,32 +462,32 @@ static public class log
} }
[StackTraceHidden] [StackTraceHidden]
static public void info( string msg, string cat = "",SourceLoc? loc = null, static public void info( string msg, string cat = "", SourceLoc? loc = null,
[CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
{ {
logBase( msg, LogType.Info, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( msg, LogType.Info, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
} }
[StackTraceHidden] [StackTraceHidden]
static public void debug( string msg, string cat = "",SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) static public void debug( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
{ {
logBase( msg, LogType.Debug, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( msg, LogType.Debug, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
} }
[StackTraceHidden] [StackTraceHidden]
static public void trace( string msg, string cat = "",SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) static public void trace( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
{ {
logBase( msg, LogType.Trace, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( msg, LogType.Trace, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
} }
[StackTraceHidden] [StackTraceHidden]
static public void warn( string msg, string cat = "",SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) static public void warn( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
{ {
logBase( msg, LogType.Warn, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( msg, LogType.Warn, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
} }
[StackTraceHidden] [StackTraceHidden]
static public void high( string msg, string cat = "",SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) static public void high( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
{ {
logBase( msg, LogType.High, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( msg, LogType.High, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
} }
@ -456,12 +522,12 @@ static public class log
[StackTraceHidden] [StackTraceHidden]
static public void fatal( string msg, string cat = "",SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) static public void fatal( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
{ {
logBase( msg, LogType.Fatal, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( msg, LogType.Fatal, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
} }
//new LogEvent( LogType.Raw, $"", "", 0, "", "lib.time", "", null ) //new LogEvent( LogType.Raw, $"", "", 0, "", "lib.time", "", null )
#endregion #endregion
@ -523,7 +589,7 @@ static public class log
foreach( var fr in stackTrace.GetFrames() ) foreach( var fr in stackTrace.GetFrames() )
{ {
logBase( $"{fr.Log}", LogType.Raw ); logBase( $"{fr.Log}", LogType.Raw );
} }
} }
@ -546,14 +612,14 @@ static public class log
} }
static public LogEvent logCreateEvent( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "",SourceLoc? loc = null ) static public LogEvent logCreateEvent( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", SourceLoc? loc = null )
{ {
LogEvent evt = new LogEvent( type, msg, dbgPath, dbgLine, dbgMethod, cat, exp, loc ); LogEvent evt = new LogEvent( type, msg, dbgPath, dbgLine, dbgMethod, cat, exp, loc );
return evt; return evt;
} }
[StackTraceHidden] [StackTraceHidden]
static public void logBase( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "",SourceLoc? loc = null ) static public void logBase( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", SourceLoc? loc = null )
{ {
var evt = logCreateEvent( msg, type, dbgPath, dbgLine, dbgMethod, cat, exp ); var evt = logCreateEvent( msg, type, dbgPath, dbgLine, dbgMethod, cat, exp );
@ -1012,13 +1078,4 @@ static public class log
private static ArrayList s_delegates = new ArrayList(); private static ArrayList s_delegates = new ArrayList();
static public Value<T> Value<T>( T val, }
[CallerArgumentExpression("val")]
string dbgExp = ""
)
{
return new( val, dbgExp );
}
} // end static class log

View File

@ -182,7 +182,7 @@ public class Ref<T> : Ref where T : class, new()
// Let's assume you'll add saving logic here. // Let's assume you'll add saving logic here.
// Mgr.Save(value, path); // Example: Needs implementation // Mgr.Save(value, path); // Example: Needs implementation
var immMeta = (value as io.Obj)?.Meta; var immMeta = ( value as io.Obj )?.Meta;
@ -433,7 +433,7 @@ public static class Mgr
var loadedObject = loaderHolder.Load( filename, reason, dbgName, dbgPath, dbgLine ); var loadedObject = loaderHolder.Load( filename, reason, dbgName, dbgPath, dbgLine );
if( loadedObject is T value ) if( loadedObject is T value )
{ {
var meta = (value as io.Obj)?.Meta; var meta = ( value as io.Obj )?.Meta;
// If it's an immutable object, record its loading. // If it's an immutable object, record its loading.
if( value is io.Obj imm ) if( value is io.Obj imm )