-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Fix namespaces * Improve test coverage * Remove UnitOfWork namespace nesting * Add first version of selectors * Add caching to selectors
- Loading branch information
1 parent
46e8191
commit 69146a7
Showing
63 changed files
with
1,943 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"version": 1, | ||
"isRoot": true, | ||
"tools": { | ||
"verify.tool": { | ||
"version": "0.6.0", | ||
"commands": [ | ||
"dotnet-verify" | ||
], | ||
"rollForward": false | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,4 +11,8 @@ bld/ | |
[Oo]bj/ | ||
msbuild.log | ||
msbuild.err | ||
msbuild.wrn | ||
msbuild.wrn | ||
|
||
.idea | ||
|
||
*.received.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
namespace Fluss.Regen.Attributes; | ||
|
||
public abstract class SelectorAttribute | ||
{ | ||
public static string FullName => $"{Namespace}.{AttributeName}"; | ||
|
||
private const string Namespace = "Fluss.Regen"; | ||
private const string AttributeName = "SelectorAttribute"; | ||
|
||
public const string AttributeSourceCode = $@"// <auto-generated/> | ||
namespace {Namespace} | ||
{{ | ||
[System.AttributeUsage(System.AttributeTargets.Method)] | ||
public class {AttributeName} : System.Attribute | ||
{{ | ||
}} | ||
}}"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard2.1</TargetFramework> | ||
<IsPackable>false</IsPackable> | ||
<Nullable>enable</Nullable> | ||
<LangVersion>latest</LangVersion> | ||
|
||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules> | ||
<IsRoslynComponent>true</IsRoslynComponent> | ||
|
||
<RootNamespace>Fluss.Regen</RootNamespace> | ||
<PackageId>Fluss.Regen</PackageId> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0"/> | ||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.0"/> | ||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" /> | ||
</ItemGroup> | ||
|
||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
using System; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Fluss.Regen.Helpers; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Text; | ||
|
||
namespace Fluss.Regen.Generators; | ||
|
||
public sealed class SelectorSyntaxGenerator : IDisposable | ||
{ | ||
private StringBuilder _sb; | ||
private CodeWriter _writer; | ||
private bool _disposed; | ||
|
||
public SelectorSyntaxGenerator() | ||
{ | ||
_sb = StringBuilderPool.Get(); | ||
_writer = new CodeWriter(_sb); | ||
} | ||
|
||
public void WriteHeader() | ||
{ | ||
_writer.WriteFileHeader(); | ||
_writer.WriteLine(); | ||
_writer.WriteIndentedLine("namespace {0}", "Fluss"); | ||
_writer.WriteIndentedLine("{"); | ||
_writer.IncreaseIndent(); | ||
} | ||
|
||
public void WriteClassHeader() | ||
{ | ||
_writer.WriteIndentedLine("public static class UnitOfWorkSelectors"); | ||
_writer.WriteIndentedLine("{"); | ||
_writer.IncreaseIndent(); | ||
_writer.WriteIndentedLine("private static global::Microsoft.Extensions.Caching.Memory.MemoryCache _cache = new (new global::Microsoft.Extensions.Caching.Memory.MemoryCacheOptions { SizeLimit = 1024 });"); | ||
} | ||
|
||
public void WriteEndNamespace() | ||
{ | ||
_writer.WriteIndentedLine(""" | ||
private record CacheEntryValue(object? Value, global::System.Collections.Generic.IReadOnlyList<global::Fluss.UnitOfWorkRecordingProxy.EventListenerTypeWithKeyAndVersion>? EventListeners); | ||
private static async ValueTask<bool> MatchesEventListenerState(IUnitOfWork unitOfWork, CacheEntryValue value) { | ||
foreach (var eventListenerData in value.EventListeners ?? global::System.Array.Empty<global::Fluss.UnitOfWorkRecordingProxy.EventListenerTypeWithKeyAndVersion>()) { | ||
if (!(await eventListenerData.IsStillUpToDate(unitOfWork))) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
"""); | ||
|
||
_writer.DecreaseIndent(); | ||
_writer.WriteIndentedLine("}"); | ||
_writer.DecreaseIndent(); | ||
_writer.WriteIndentedLine("}"); | ||
_writer.WriteLine(); | ||
} | ||
|
||
public void WriteMethodSignatureStart(string methodName, ITypeSymbol returnType, bool noParameters) | ||
{ | ||
_writer.WriteLine(); | ||
_writer.WriteIndentedLine( | ||
"public static async global::{0}<{1}> Select{2}(this global::Fluss.IUnitOfWork unitOfWork{3}", | ||
typeof(ValueTask).FullName, | ||
returnType.ToFullyQualified(), | ||
methodName, | ||
noParameters ? "" : ", "); | ||
_writer.IncreaseIndent(); | ||
} | ||
|
||
public void WriteMethodSignatureParameter(ITypeSymbol parameterType, string parameterName, bool isLast) | ||
{ | ||
_writer.WriteIndentedLine( | ||
"{0} {1}{2}", | ||
parameterType.ToFullyQualified(), | ||
parameterName, | ||
isLast ? "" : "," | ||
); | ||
} | ||
|
||
public void WriteMethodSignatureEnd() | ||
{ | ||
_writer.DecreaseIndent(); | ||
_writer.WriteIndentedLine(")"); | ||
_writer.WriteIndentedLine("{"); | ||
_writer.IncreaseIndent(); | ||
} | ||
|
||
public void WriteRecordingUnitOfWork() | ||
{ | ||
_writer.WriteIndentedLine("var recordingUnitOfWork = new global::Fluss.UnitOfWorkRecordingProxy(unitOfWork);"); | ||
} | ||
|
||
public void WriteKeyStart(string containingType, string methodName, bool noParameters) | ||
{ | ||
_writer.WriteIndentedLine("var key = ("); | ||
_writer.IncreaseIndent(); | ||
_writer.WriteIndentedLine("\"{0}.{1}\"{2}", containingType, methodName, noParameters ? "" : ","); | ||
} | ||
|
||
public void WriteKeyParameter(string parameterName, bool isLast) | ||
{ | ||
_writer.WriteIndentedLine("{0}{1}", parameterName, isLast ? "" : ","); | ||
} | ||
|
||
public void WriteKeyEnd() | ||
{ | ||
_writer.DecreaseIndent(); | ||
_writer.WriteIndentedLine(");"); | ||
_writer.WriteLine(); | ||
} | ||
|
||
public void WriteMethodCacheHit(ITypeSymbol returnType) | ||
{ | ||
_writer.WriteIndented("if (_cache.TryGetValue(key, out var result) && result is CacheEntryValue entryValue && await MatchesEventListenerState(unitOfWork, entryValue)) "); | ||
using (_writer.WriteBraces()) | ||
{ | ||
_writer.WriteIndentedLine("return ({0})entryValue.Value;", returnType.ToFullyQualified()); | ||
} | ||
_writer.WriteLine(); | ||
} | ||
|
||
public void WriteMethodCall(string containingType, string methodName, bool isAsync) | ||
{ | ||
_writer.WriteIndentedLine("result = {0}global::{1}.{2}(", isAsync ? "await " : "", containingType, methodName); | ||
_writer.IncreaseIndent(); | ||
} | ||
|
||
public void WriteMethodCallParameter(string parameterName, bool isLast) | ||
{ | ||
_writer.WriteIndentedLine("{0}{1}", parameterName, isLast ? "" : ","); | ||
} | ||
|
||
public void WriteMethodCallEnd(bool isAsync) | ||
{ | ||
_writer.DecreaseIndent(); | ||
_writer.WriteIndentedLine("){0};", isAsync ? ".ConfigureAwait(false)" : ""); | ||
_writer.WriteLine(); | ||
} | ||
|
||
public void WriteMethodCacheMiss(ITypeSymbol returnType) | ||
{ | ||
_writer.WriteIndented("using (var entry = _cache.CreateEntry(key)) "); | ||
|
||
using (_writer.WriteBraces()) | ||
{ | ||
_writer.WriteIndentedLine("entry.Value = new CacheEntryValue(result, recordingUnitOfWork.GetRecordedListeners());"); | ||
_writer.WriteIndentedLine("entry.Size = 1;"); | ||
} | ||
|
||
_writer.WriteLine(); | ||
_writer.WriteIndentedLine("return ({0})result;", returnType.ToFullyQualified()); | ||
} | ||
|
||
public void WriteMethodEnd() | ||
{ | ||
_writer.DecreaseIndent(); | ||
_writer.WriteIndentedLine("}"); | ||
} | ||
|
||
public override string ToString() | ||
=> _sb.ToString(); | ||
|
||
public SourceText ToSourceText() | ||
=> SourceText.From(ToString(), Encoding.UTF8); | ||
|
||
public void Dispose() | ||
{ | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
|
||
StringBuilderPool.Return(_sb); | ||
_sb = default!; | ||
_writer = default!; | ||
_disposed = true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Text; | ||
using System.Threading; | ||
|
||
namespace Fluss.Regen.Generators; | ||
|
||
public static class StringBuilderPool | ||
{ | ||
private static StringBuilder? _stringBuilder; | ||
|
||
public static StringBuilder Get() | ||
{ | ||
var stringBuilder = Interlocked.Exchange(ref _stringBuilder, null); | ||
return stringBuilder ?? new StringBuilder(); | ||
} | ||
|
||
public static void Return(StringBuilder stringBuilder) | ||
{ | ||
stringBuilder.Clear(); | ||
Interlocked.CompareExchange(ref _stringBuilder, stringBuilder, null); | ||
} | ||
} |
Oops, something went wrong.