164 lines
3.5 KiB
C#
164 lines
3.5 KiB
C#
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<T>
|
|
where T : Versioned<T>
|
|
{
|
|
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<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>
|
|
{
|
|
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<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
|
|
{
|
|
//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<T> : Recorded<T>
|
|
where T : Timed<T>
|
|
{
|
|
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<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
|
|
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
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|