refactor: Remove ForEach discovery, cache MethodInfo
Remove ForEach type argument collection from source generator. Cache MethodInfo for RemoveComponentImpl in World.cs. Update API docs for IRelationship and ChangeKind.
This commit is contained in:
parent
8a32588c54
commit
53fa3b742d
|
|
@ -53,10 +53,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
|||
"RemoveSingleton",
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> _forEachNames = new()
|
||||
{
|
||||
"ForEach",
|
||||
};
|
||||
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
|
|
@ -68,15 +65,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
|||
.Where(t => t.FullyQualifiedName != null)
|
||||
.Select((t, _) => (t.FullyQualifiedName!, t.AssemblyQualifiedName!, t.IsRelationship, t.IsSingleton));
|
||||
|
||||
// Also collect ForEach type arguments from the World class.
|
||||
var forEachCalls = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
predicate: IsForEachCandidate,
|
||||
transform: ExtractForEachTypes)
|
||||
.Where(list => list.Length > 0)
|
||||
.SelectMany((list, _) => list);
|
||||
|
||||
var allTypes = invocations.Collect().Combine(forEachCalls.Collect());
|
||||
var allTypes = invocations.Collect();
|
||||
|
||||
context.RegisterSourceOutput(allTypes, GenerateRegistry);
|
||||
}
|
||||
|
|
@ -97,21 +86,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
|||
return false;
|
||||
}
|
||||
|
||||
private static bool IsForEachCandidate(SyntaxNode node, CancellationToken _)
|
||||
{
|
||||
if (node is not InvocationExpressionSyntax invocation)
|
||||
return false;
|
||||
|
||||
if (invocation.Expression is MemberAccessExpressionSyntax memberAccess)
|
||||
{
|
||||
var name = memberAccess.Name is GenericNameSyntax gn
|
||||
? gn.Identifier.Text
|
||||
: memberAccess.Name.Identifier.Text;
|
||||
return _forEachNames.Contains(name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static (string? FullyQualifiedName, string? AssemblyQualifiedName, bool IsRelationship, bool IsSingleton) ExtractComponentType(
|
||||
GeneratorSyntaxContext ctx, CancellationToken _)
|
||||
|
|
@ -154,44 +129,11 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
|||
return (fqn, aqn, isRelationship, isSingleton);
|
||||
}
|
||||
|
||||
private static ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> ExtractForEachTypes(
|
||||
GeneratorSyntaxContext ctx, CancellationToken _)
|
||||
{
|
||||
if (ctx.Node is not InvocationExpressionSyntax invocation)
|
||||
return ImmutableArray<(string, string, bool)>.Empty;
|
||||
|
||||
if (invocation.Expression is not MemberAccessExpressionSyntax memberAccess)
|
||||
return ImmutableArray<(string, string, bool)>.Empty;
|
||||
|
||||
if (memberAccess.Name is not GenericNameSyntax genericName)
|
||||
return ImmutableArray<(string, string, bool)>.Empty;
|
||||
|
||||
var types = ImmutableArray.CreateBuilder<(string, string, bool)>();
|
||||
foreach (var typeArg in genericName.TypeArgumentList.Arguments)
|
||||
{
|
||||
var symbolInfo = ctx.SemanticModel.GetSymbolInfo(typeArg);
|
||||
if (symbolInfo.Symbol is INamedTypeSymbol typeSymbol &&
|
||||
typeSymbol.IsValueType && !typeSymbol.IsAbstract &&
|
||||
typeSymbol.DeclaredAccessibility == Accessibility.Public)
|
||||
{
|
||||
var fqn = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var aqn = typeSymbol.ContainingAssembly != null
|
||||
? $"{typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted))}, {typeSymbol.ContainingAssembly.Name}"
|
||||
: fqn;
|
||||
bool isRelationship = typeSymbol.AllInterfaces.Any(i =>
|
||||
i.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::OECS.IRelationship");
|
||||
types.Add((fqn, aqn, isRelationship));
|
||||
}
|
||||
}
|
||||
|
||||
return types.ToImmutable();
|
||||
}
|
||||
|
||||
private static void GenerateRegistry(SourceProductionContext context,
|
||||
(ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship, bool IsSingleton)> Left,
|
||||
ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> Right) data)
|
||||
ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship, bool IsSingleton)> invocations)
|
||||
{
|
||||
var (invocations, forEachTypes) = data;
|
||||
|
||||
// Collect unique types by fully-qualified name, deduplicating.
|
||||
var typeMap = new Dictionary<string, (string Fqn, string Aqn, bool IsRel, bool IsSingleton)>();
|
||||
|
|
@ -202,16 +144,6 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
|||
else
|
||||
typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship, t.IsSingleton);
|
||||
}
|
||||
foreach (var t in forEachTypes)
|
||||
{
|
||||
if (!typeMap.ContainsKey(t.FullyQualifiedName))
|
||||
typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship, false);
|
||||
else if (t.IsRelationship)
|
||||
{
|
||||
var existing = typeMap[t.FullyQualifiedName];
|
||||
typeMap[t.FullyQualifiedName] = (existing.Fqn, existing.Aqn, true, existing.IsSingleton);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeMap.Count == 0)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -194,6 +194,11 @@ public class World : IDisposable
|
|||
nameof(AddComponentImpl),
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!;
|
||||
|
||||
private static readonly System.Reflection.MethodInfo s_removeComponentImpl =
|
||||
typeof(World).GetMethod(
|
||||
nameof(RemoveComponentImpl),
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!;
|
||||
|
||||
private void AddComponentImpl<T>(Entity entity, T component) where T : struct
|
||||
{
|
||||
ThrowIfNotAlive(entity);
|
||||
|
|
@ -589,20 +594,13 @@ public class World : IDisposable
|
|||
switch (m.Kind)
|
||||
{
|
||||
case PendingMutationKind.AddComponent:
|
||||
// Use reflection to call AddComponentImpl<T>.
|
||||
var addMethod = typeof(World).GetMethod(
|
||||
nameof(AddComponentImpl),
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!;
|
||||
var genericAdd = addMethod.MakeGenericMethod(m.ComponentType);
|
||||
genericAdd.Invoke(this, [m.Entity, m.Component]);
|
||||
s_addComponentImpl.MakeGenericMethod(m.ComponentType)
|
||||
.Invoke(this, [m.Entity, m.Component]);
|
||||
break;
|
||||
|
||||
case PendingMutationKind.RemoveComponent:
|
||||
var removeMethod = typeof(World).GetMethod(
|
||||
nameof(RemoveComponentImpl),
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!;
|
||||
var genericRemove = removeMethod.MakeGenericMethod(m.ComponentType);
|
||||
genericRemove.Invoke(this, [m.Entity]);
|
||||
s_removeComponentImpl.MakeGenericMethod(m.ComponentType)
|
||||
.Invoke(this, [m.Entity]);
|
||||
break;
|
||||
|
||||
case PendingMutationKind.DestroyEntity:
|
||||
|
|
|
|||
|
|
@ -379,7 +379,6 @@ namespace OECS;
|
|||
|
||||
public interface IRelationship
|
||||
{
|
||||
Entity Source { get; }
|
||||
Entity Target { get; }
|
||||
}
|
||||
```
|
||||
|
|
@ -399,8 +398,7 @@ namespace OECS;
|
|||
public struct Relationship<TSelf, TTarget> : IRelationship
|
||||
where TSelf : struct where TTarget : struct
|
||||
{
|
||||
[Key(0)] public Entity Source { get; set; }
|
||||
[Key(1)] public Entity Target { get; set; }
|
||||
[Key(0)] public Entity Target { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -424,7 +422,8 @@ public enum ChangeKind
|
|||
EntityRemoved,
|
||||
ComponentAdded,
|
||||
ComponentRemoved,
|
||||
ComponentModified
|
||||
ComponentModified,
|
||||
RelationshipReordered
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue