Initial commit: Unity WordConnect project

This commit is contained in:
2025-08-01 19:12:05 +08:00
commit f14db75802
3503 changed files with 448337 additions and 0 deletions

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using VContainer.Internal;
namespace VContainer.Diagnostics
{
public sealed class DiagnosticsCollector
{
public string ScopeName { get; }
readonly List<DiagnosticsInfo> diagnosticsInfos = new List<DiagnosticsInfo>();
readonly ThreadLocal<Stack<DiagnosticsInfo>> resolveCallStack
= new ThreadLocal<Stack<DiagnosticsInfo>>(() => new Stack<DiagnosticsInfo>());
public DiagnosticsCollector(string scopeName)
{
ScopeName = scopeName;
}
public IReadOnlyList<DiagnosticsInfo> GetDiagnosticsInfos()
{
return diagnosticsInfos;
}
public void Clear()
{
lock (diagnosticsInfos)
{
diagnosticsInfos.Clear();
}
}
public void TraceRegister(RegisterInfo registerInfo)
{
lock (diagnosticsInfos)
{
diagnosticsInfos.Add(new DiagnosticsInfo(ScopeName, registerInfo));
}
}
public void TraceBuild(RegistrationBuilder registrationBuilder, Registration registration)
{
lock (diagnosticsInfos)
{
foreach (var x in diagnosticsInfos)
{
if (x.RegisterInfo.RegistrationBuilder == registrationBuilder)
{
x.ResolveInfo = new ResolveInfo(registration);
return;
}
}
}
}
public object TraceResolve(Registration registration, Func<Registration, object> resolving)
{
var current = DiagnositcsContext.FindByRegistration(registration);
var owner = resolveCallStack.Value.Count > 0 ? resolveCallStack.Value.Peek() : null;
if (!(registration.Provider is CollectionInstanceProvider) && current != null && current != owner)
{
current.ResolveInfo.RefCount += 1;
current.ResolveInfo.MaxDepth = current.ResolveInfo.MaxDepth < 0
? resolveCallStack.Value.Count
: Math.Max(current.ResolveInfo.MaxDepth, resolveCallStack.Value.Count);
owner?.Dependencies.Add(current);
resolveCallStack.Value.Push(current);
var watch = Stopwatch.StartNew();
var instance = resolving(registration);
watch.Stop();
resolveCallStack.Value.Pop();
SetResolveTime(current, watch.ElapsedMilliseconds);
if (!current.ResolveInfo.Instances.Contains(instance))
{
current.ResolveInfo.Instances.Add(instance);
}
return instance;
}
return resolving(registration);
}
private static void SetResolveTime(DiagnosticsInfo current, long elapsedMilliseconds)
{
var resolves = current.ResolveInfo.RefCount;
var resolveTime = current.ResolveInfo.ResolveTime;
switch (current.ResolveInfo.Registration.Lifetime)
{
case Lifetime.Transient:
resolveTime = (resolveTime * (resolves - 1) + elapsedMilliseconds) / resolves;
break;
case Lifetime.Scoped:
case Lifetime.Singleton:
if (elapsedMilliseconds > resolveTime)
resolveTime = elapsedMilliseconds;
break;
default:
throw new ArgumentOutOfRangeException();
}
current.ResolveInfo.ResolveTime = resolveTime;
}
public void NotifyContainerBuilt(IObjectResolver container)
=> DiagnositcsContext.NotifyContainerBuilt(container);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 689fb82515a24c2887f2693a3a11010b
timeCreated: 1632059581

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace VContainer.Diagnostics
{
public static class DiagnositcsContext
{
static readonly Dictionary<string, DiagnosticsCollector> collectors
= new Dictionary<string, DiagnosticsCollector>();
public static event Action<IObjectResolver> OnContainerBuilt;
public static DiagnosticsCollector GetCollector(string name)
{
lock (collectors)
{
if (!collectors.TryGetValue(name, out var collector))
{
collector = new DiagnosticsCollector(name);
collectors.Add(name, collector);
}
return collector;
}
}
public static ILookup<string, DiagnosticsInfo> GetGroupedDiagnosticsInfos()
{
lock (collectors)
{
return collectors
.SelectMany(x => x.Value.GetDiagnosticsInfos())
.Where(x => x.ResolveInfo.MaxDepth <= 1)
.ToLookup(x => x.ScopeName);
}
}
public static IEnumerable<DiagnosticsInfo> GetDiagnosticsInfos()
{
lock (collectors)
{
return collectors.SelectMany(x => x.Value.GetDiagnosticsInfos());
}
}
public static void NotifyContainerBuilt(IObjectResolver container)
{
OnContainerBuilt?.Invoke(container);
}
internal static DiagnosticsInfo FindByRegistration(Registration registration)
{
return GetDiagnosticsInfos().FirstOrDefault(x => x.ResolveInfo.Registration == registration);
}
public static void RemoveCollector(string name)
{
lock (collectors)
{
collectors.Remove(name);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a87e62523cc246f2917f3ba78f7c6e99
timeCreated: 1633441412

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace VContainer.Diagnostics
{
public sealed class DiagnosticsInfo
{
public string ScopeName { get; }
public RegisterInfo RegisterInfo { get; }
public ResolveInfo ResolveInfo { get; set; }
public List<DiagnosticsInfo> Dependencies { get; } = new List<DiagnosticsInfo>();
public DiagnosticsInfo(string scopeName, RegisterInfo registerInfo)
{
ScopeName = scopeName;
RegisterInfo = registerInfo;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: af9e78dd14ec4031998bbf9c34cc93ae
timeCreated: 1633441316

View File

@ -0,0 +1,119 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Threading;
namespace VContainer.Diagnostics
{
public sealed class RegisterInfo
{
static bool displayFileNames = true;
static int idSeed;
public int Id { get; }
public RegistrationBuilder RegistrationBuilder { get; }
public StackTrace StackTrace { get; }
StackFrame headLineStackFrame;
internal string formattedStackTrace = default; // cache field for internal use(Unity Editor, etc...)
public RegisterInfo(RegistrationBuilder registrationBuilder)
{
Id = Interlocked.Increment(ref idSeed);
RegistrationBuilder = registrationBuilder;
StackTrace = new StackTrace(true);
headLineStackFrame = GetHeadlineFrame(StackTrace);
}
public string GetFilename()
{
if (headLineStackFrame != null && displayFileNames && headLineStackFrame.GetILOffset() != -1)
{
try
{
return headLineStackFrame.GetFileName();
}
catch (NotSupportedException)
{
displayFileNames = false;
}
catch (SecurityException)
{
displayFileNames = false;
}
}
return null;
}
public int GetFileLineNumber()
{
if (headLineStackFrame != null && displayFileNames && headLineStackFrame.GetILOffset() != -1)
{
try
{
return headLineStackFrame.GetFileLineNumber();
}
catch (NotSupportedException)
{
displayFileNames = false;
}
catch (SecurityException)
{
displayFileNames = false;
}
}
return -1;
}
public string GetScriptAssetPath()
{
var filename = GetFilename();
if (filename == null)
return "";
var prefixIndex = filename.LastIndexOf("Assets/");
return prefixIndex > 0 ? filename.Substring(prefixIndex) : "";
}
public string GetHeadline()
{
if (headLineStackFrame == null)
return "";
var method = headLineStackFrame.GetMethod();
var filename = GetFilename();
if (filename != null)
{
var lineNumber = GetFileLineNumber();
return $"{method.DeclaringType?.FullName}.{method.Name} (at {Path.GetFileName(filename)}:{lineNumber})";
}
var ilOffset = headLineStackFrame.GetILOffset();
if (ilOffset != -1)
{
return $"{method.DeclaringType?.FullName}.{method.Name}(offset: {ilOffset})";
}
return $"{method.DeclaringType?.FullName}.{method.Name}";
}
StackFrame GetHeadlineFrame(StackTrace stackTrace)
{
for (var i = 0; i < stackTrace.FrameCount; i++)
{
var sf = stackTrace.GetFrame(i);
if (sf == null) continue;
var m = sf.GetMethod();
if (m == null) continue;
if (m.DeclaringType == null) continue;
if (m.DeclaringType.Namespace == null || !m.DeclaringType.Namespace.StartsWith("VContainer"))
{
return sf;
}
}
return stackTrace.FrameCount > 0 ? stackTrace.GetFrame(0) : null;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4359f1f8bb3b4540835998a60eb93049
timeCreated: 1633272541

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace VContainer.Diagnostics
{
public sealed class ResolveInfo
{
public Registration Registration { get; }
public List<object> Instances { get; } = new List<object>();
public int MaxDepth { get; set; } = -1;
public int RefCount { get; set; }
public long ResolveTime { get; set; }
public ResolveInfo(Registration registration)
{
Registration = registration;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3f53a6c226cf4a04ae556c00dc477f4b
timeCreated: 1633102576