using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; // A spot for immutable helpers namespace imm { public record class Versioned where T : Versioned { public delegate void ChangeDelegate( T old, T next ); public uint Version { get; protected set; } = 0; public string Reason { get; protected set; } = ""; public ChangeDelegate OnChange; public T Process( Func fn, string reason = "" ) { var newT = fn( ( T )this ); return newT with { Version = newT.Version + 1, Reason = reason, }; } } public record class Recorded : Versioned where T : Recorded { public T? Old { get; protected set; } public string Expression { get; protected set; } = ""; public string MemberName { get; protected set; } = ""; public string FilePath { get; protected set; } = ""; public int LineNumber { get; protected set; } = -1; public T Record( string reason = "", [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0 ) { var orig = ( T )this; var next = ( T ) this with { //Do the Versioned code here Version = orig.Version + 1, Reason = reason, Old = orig, MemberName = memberName, FilePath = filePath, LineNumber = lineNumber, }; OnChange( orig, next ); return next; } public T Process( Func 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 { //Do the Versioned code here Version = orig.Version + 1, Reason = reason, //Recorded Old = orig, Expression = expression, MemberName = memberName, FilePath = filePath, LineNumber = lineNumber, }; OnChange( orig, ret ); return ret; } } public record class Timed : Recorded where T : Timed { public readonly DateTime CreatedAt = DateTime.Now; public DateTime TouchedAt { get; set; } = DateTime.Now; 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 ); } new public T Process( Func 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 Version = orig.Version + 1, Reason = reason, //Recorded Old = orig, Expression = expression, MemberName = memberName, FilePath = filePath, LineNumber = lineNumber, //Timed TouchedAt = DateTime.Now, }; OnChange( orig, ret ); return ret; } } public static class Util { } }