Various immutable changes
This commit is contained in:
parent
dbdd6ea748
commit
71a7a115e2
300
imm/Imm.cs
300
imm/Imm.cs
@ -9,155 +9,237 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
// A spot for immutable helpers
|
// A spot for immutable helpers
|
||||||
|
|
||||||
namespace imm
|
// TODO
|
||||||
|
// TODO
|
||||||
|
// TODO
|
||||||
|
// x) Wrap metadata into its own struct
|
||||||
|
|
||||||
|
namespace imm;
|
||||||
|
|
||||||
|
|
||||||
|
static public class Util
|
||||||
{
|
{
|
||||||
|
//This can handle both Timed and Recorded
|
||||||
public record class Versioned<T>
|
static public T Process<T>( ref T obj, Func<T, T> fn, string reason = "",
|
||||||
where T : Versioned<T>
|
[CallerMemberName] string memberName = "",
|
||||||
{
|
[CallerFilePath] string filePath = "",
|
||||||
public delegate void ChangeDelegate( T old, T next );
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerArgumentExpression("fn")]
|
||||||
public uint Version { get; protected set; } = 0;
|
string expression = default )
|
||||||
public string Reason { get; protected set; } = "";
|
|
||||||
|
|
||||||
public ChangeDelegate OnChange;
|
|
||||||
|
|
||||||
public T Process( Func<T, T> fn, string reason = "" )
|
|
||||||
{
|
|
||||||
var newT = fn( ( T )this );
|
|
||||||
|
|
||||||
return newT with
|
|
||||||
{
|
|
||||||
Version = newT.Version + 1,
|
|
||||||
Reason = reason,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record class Recorded<T> : Versioned<T>
|
|
||||||
where T : Recorded<T>
|
where T : Recorded<T>
|
||||||
{
|
{
|
||||||
public T? Old { get; protected set; }
|
obj = obj.Process( fn, reason, memberName, filePath, lineNumber, expression );
|
||||||
public string Expression { get; protected set; } = "";
|
return obj;
|
||||||
public string MemberName { get; protected set; } = "";
|
}
|
||||||
public string FilePath { get; protected set; } = "";
|
|
||||||
public int LineNumber { get; protected set; } = -1;
|
|
||||||
|
|
||||||
public T Record( string reason = "",
|
//This can handle both Timed and Recorded
|
||||||
[CallerMemberName] string memberName = "",
|
static public T Versioned<T>( ref T obj, Func<T, T> fn, string reason = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerMemberName] string memberName = "",
|
||||||
[CallerLineNumber] int lineNumber = 0 )
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerArgumentExpression("fn")]
|
||||||
|
string expression = default )
|
||||||
|
where T : Versioned<T>
|
||||||
|
{
|
||||||
|
obj = obj.Process( fn, reason );
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public record class Versioned<T>
|
||||||
|
where T : Versioned<T>
|
||||||
|
{
|
||||||
|
public delegate void ChangeDelegate( T ZZOld, T next );
|
||||||
|
|
||||||
|
public record class MetaData
|
||||||
|
{
|
||||||
|
public uint Version { get; internal set; } = 0;
|
||||||
|
public string Reason { get; internal set; } = "";
|
||||||
|
|
||||||
|
public MetaData() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Versioned( MetaData meta )
|
||||||
|
{
|
||||||
|
MetaStorage = meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal MetaData MetaStorage = new();
|
||||||
|
|
||||||
|
public MetaData Meta => MetaStorage;
|
||||||
|
|
||||||
|
public ChangeDelegate OnChange;
|
||||||
|
|
||||||
|
public T Process( Func<T, T> fn, string reason = "" )
|
||||||
|
{
|
||||||
|
var newT = fn( ( T )this );
|
||||||
|
|
||||||
|
return newT with
|
||||||
{
|
{
|
||||||
var orig = ( T )this;
|
MetaStorage = Meta with
|
||||||
|
|
||||||
var next = ( T ) this with
|
|
||||||
{
|
{
|
||||||
//Do the Versioned code here
|
Version = newT.Meta.Version + 1,
|
||||||
Version = orig.Version + 1,
|
Reason = reason,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record class Recorded<T> : Versioned<T>
|
||||||
|
where T : Recorded<T>
|
||||||
|
{
|
||||||
|
new public record class MetaData : Versioned<T>.MetaData
|
||||||
|
{
|
||||||
|
public T? ZZOld { get; internal set; }
|
||||||
|
public T? Old => ZZOld;
|
||||||
|
public string Expression { get; internal set; } = "";
|
||||||
|
public string MemberName { get; internal set; } = "";
|
||||||
|
public string FilePath { get; internal set; } = "";
|
||||||
|
public int LineNumber { get; internal set; } = -1;
|
||||||
|
|
||||||
|
public MetaData() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Recorded() : this( new MetaData() )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Recorded(MetaData meta) : base( meta )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
new public MetaData Meta => MetaStorage as MetaData;
|
||||||
|
|
||||||
|
|
||||||
|
virtual public T Record( string reason = "",
|
||||||
|
[CallerMemberName] string memberName = "",
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0 )
|
||||||
|
{
|
||||||
|
return Process( t => t, reason, memberName, filePath, lineNumber );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual public T Process( T next, string reason = "",
|
||||||
|
[CallerMemberName] string memberName = "",
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerArgumentExpression("next")]
|
||||||
|
string expression = default )
|
||||||
|
{
|
||||||
|
return Process( ( old ) => next, reason, memberName, filePath, lineNumber, expression );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual public T Process( Func<T, T> fn, string reason = "",
|
||||||
|
[CallerMemberName] string memberName = "",
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerArgumentExpression("fn")]
|
||||||
|
string expression = default )
|
||||||
|
{
|
||||||
|
var orig = ( T )this;
|
||||||
|
|
||||||
|
var next = fn( orig );
|
||||||
|
|
||||||
|
var ret = next with
|
||||||
|
{
|
||||||
|
//Do the Versioned code here
|
||||||
|
MetaStorage = Meta with
|
||||||
|
{
|
||||||
|
Version = orig.Meta.Version + 1,
|
||||||
Reason = reason,
|
Reason = reason,
|
||||||
|
|
||||||
Old = orig,
|
ZZOld = orig,
|
||||||
MemberName = memberName,
|
MemberName = memberName,
|
||||||
FilePath = filePath,
|
FilePath = filePath,
|
||||||
LineNumber = lineNumber,
|
LineNumber = lineNumber,
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
OnChange( orig, next );
|
OnChange( orig, ret );
|
||||||
|
|
||||||
return next;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public T Process( Func<T, T> fn, string reason = "",
|
|
||||||
[CallerMemberName] string memberName = "",
|
|
||||||
[CallerFilePath] string filePath = "",
|
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
|
||||||
[CallerArgumentExpression("fn")]
|
|
||||||
string expression = default )
|
|
||||||
{
|
|
||||||
var orig = ( T )this;
|
|
||||||
|
|
||||||
var next = ( T )fn( orig );
|
public record class Timed<T> : Recorded<T>
|
||||||
|
where T : Timed<T>
|
||||||
|
{
|
||||||
|
|
||||||
var ret = ( T )next with
|
new public record class MetaData : Recorded<T>.MetaData
|
||||||
{
|
{
|
||||||
//Do the Versioned code here
|
public readonly DateTime CreatedAt = DateTime.Now;
|
||||||
Version = orig.Version + 1,
|
public DateTime TouchedAt { get; internal set; } = DateTime.Now;
|
||||||
Reason = reason,
|
}
|
||||||
|
|
||||||
//Recorded
|
public Timed() : this( new MetaData() )
|
||||||
Old = orig,
|
{
|
||||||
Expression = expression,
|
}
|
||||||
MemberName = memberName,
|
|
||||||
FilePath = filePath,
|
|
||||||
LineNumber = lineNumber,
|
|
||||||
};
|
|
||||||
|
|
||||||
OnChange( orig, ret );
|
public Timed( MetaData meta ) : base( meta )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
new public MetaData Meta => MetaStorage as MetaData;
|
||||||
}
|
|
||||||
|
public TimeSpan Since => Meta.TouchedAt - Meta.Old?.Meta.TouchedAt ?? TimeSpan.MaxValue;
|
||||||
|
|
||||||
|
|
||||||
|
override public T Record( string reason = "",
|
||||||
|
[CallerMemberName] string memberName = "",
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0 )
|
||||||
|
{
|
||||||
|
return Process( t => t, reason, memberName, filePath, lineNumber );
|
||||||
|
}
|
||||||
|
|
||||||
|
override public T Process( T next, string reason = "",
|
||||||
|
[CallerMemberName] string memberName = "",
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerArgumentExpression("next")]
|
||||||
|
string expression = default )
|
||||||
|
{
|
||||||
|
return Process( ( old ) => next, reason, memberName, filePath, lineNumber, expression );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public record class Timed<T> : Recorded<T>
|
override public T Process( Func<T, T> fn, string reason = "",
|
||||||
where T : Timed<T>
|
[CallerMemberName] string memberName = "",
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerArgumentExpression("fn")]
|
||||||
|
string expression = default )
|
||||||
{
|
{
|
||||||
public readonly DateTime CreatedAt = DateTime.Now;
|
var orig = ( T )this;
|
||||||
public DateTime TouchedAt { get; set; } = DateTime.Now;
|
|
||||||
|
|
||||||
|
var next = fn( orig );
|
||||||
|
|
||||||
public T Process( T next, string reason = "",
|
var ret = next with
|
||||||
[CallerMemberName] string memberName = "",
|
|
||||||
[CallerFilePath] string filePath = "",
|
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
|
||||||
[CallerArgumentExpression("next")]
|
|
||||||
string expression = default )
|
|
||||||
{
|
{
|
||||||
return Process( ( old ) => next, reason, memberName, filePath, lineNumber, expression );
|
MetaStorage = Meta with
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
new public T Process( Func<T, T> fn, string reason = "",
|
|
||||||
[CallerMemberName] string memberName = "",
|
|
||||||
[CallerFilePath] string filePath = "",
|
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
|
||||||
[CallerArgumentExpression("fn")]
|
|
||||||
string expression = default )
|
|
||||||
{
|
|
||||||
var orig = ( T )this;
|
|
||||||
|
|
||||||
var next = ( T )fn( orig );
|
|
||||||
|
|
||||||
var ret = ( T )next with
|
|
||||||
{
|
{
|
||||||
//Versioned
|
//Versioned
|
||||||
Version = orig.Version + 1,
|
Version = orig.Meta.Version + 1,
|
||||||
Reason = reason,
|
Reason = reason,
|
||||||
|
|
||||||
//Recorded
|
//Recorded
|
||||||
Old = orig,
|
|
||||||
Expression = expression,
|
|
||||||
MemberName = memberName,
|
MemberName = memberName,
|
||||||
FilePath = filePath,
|
FilePath = filePath,
|
||||||
LineNumber = lineNumber,
|
LineNumber = lineNumber,
|
||||||
|
ZZOld = orig,
|
||||||
|
|
||||||
//Timed
|
//Timed
|
||||||
TouchedAt = DateTime.Now,
|
TouchedAt = DateTime.Now,
|
||||||
};
|
}
|
||||||
|
|
||||||
OnChange( orig, ret );
|
};
|
||||||
|
|
||||||
return ret;
|
if( OnChange != null) OnChange( orig, ret );
|
||||||
}
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Util
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,8 @@ static public class log
|
|||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
File = 1 << 0,
|
File = 1 << 0,
|
||||||
Console = 1 << 1,
|
Console = 1 << 1,
|
||||||
|
|
||||||
|
All = File | Console,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -88,9 +88,9 @@ namespace lib
|
|||||||
|
|
||||||
public class XmlFormatter2Cfg: Config
|
public class XmlFormatter2Cfg: Config
|
||||||
{
|
{
|
||||||
public readonly Datastructure datastructure = Datastructure.Graph;
|
public Datastructure datastructure = Datastructure.Graph;
|
||||||
|
|
||||||
public readonly int Version = 2;
|
public int Version = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class XmlFormatter2: IFormatter
|
public class XmlFormatter2: IFormatter
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user