From a7ea817976ccb7f078b303e73b18a459117ba0d4 Mon Sep 17 00:00:00 2001 From: Thad House Date: Sat, 17 Feb 2024 18:57:57 -0800 Subject: [PATCH] Everything but ILogged --- .../LoggableMember.cs | 81 ++--- .../LoggableType.cs | 292 +++++------------- src/thirdparty/Stereologue/Stereologuer.cs | 22 +- src/wpiutil/Logging/StructArrayLogEntry.cs | 14 +- test/stereologue.test/TestTree.cs | 8 + 5 files changed, 131 insertions(+), 286 deletions(-) diff --git a/sourcegeneration/StereologueSourceGenerator/LoggableMember.cs b/sourcegeneration/StereologueSourceGenerator/LoggableMember.cs index e48ae737..4cadcb4d 100644 --- a/sourcegeneration/StereologueSourceGenerator/LoggableMember.cs +++ b/sourcegeneration/StereologueSourceGenerator/LoggableMember.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; namespace Stereologue.SourceGenerator; @@ -16,14 +17,7 @@ internal enum DeclarationType Logged, Struct, Protobuf, - Boolean, - Float, - Double, - Integer, - String, - Raw, - Char, - ULong, + SpecialType, } internal enum DeclarationKind @@ -38,8 +32,10 @@ internal enum DeclarationKind NullableReferenceType } +internal record MemberDeclaration(DeclarationType LoggedType, SpecialType SpecialType, DeclarationKind LoggedKind, string? FQN); + // Contains all information about a loggable member -internal record LoggableMember(string Name, MemberType MemberType, DeclarationType LoggedType, DeclarationKind LoggedKind, LogAttributeInfo AttributeInfo); +internal record LoggableMember(string Name, MemberType MemberType, MemberDeclaration MemberDeclaration, LogAttributeInfo AttributeInfo); internal static class LoggableMemberExtensions { @@ -87,7 +83,7 @@ private static DeclarationKind GetInnerType(this ITypeSymbol typeSymbol, out ITy return innerType.IsReferenceType ? DeclarationKind.NullableReferenceType : DeclarationKind.None; } - private static (DeclarationType, DeclarationKind)? GetDeclarationType(this ITypeSymbol typeSymbol, LogAttributeInfo attributeInfo, CancellationToken token) + private static MemberDeclaration? GetDeclarationType(this ITypeSymbol typeSymbol, LogAttributeInfo attributeInfo, CancellationToken token) { token.ThrowIfCancellationRequested(); @@ -95,16 +91,24 @@ private static (DeclarationType, DeclarationKind)? GetDeclarationType(this IType token.ThrowIfCancellationRequested(); + // TODO support IntPtr and NIntPtr + + if (typeSymbol.SpecialType != SpecialType.None) + { + // We're a built in special type, no need to check for anything else + return new(DeclarationType.SpecialType, typeSymbol.SpecialType, nestedKind, null); + } + // If we know we're generating a loggable implementation if (typeSymbol.GetAttributes().Where(x => x.AttributeClass?.ToDisplayString() == "Stereologue.GenerateLogAttribute").Any()) { - return (DeclarationType.Logged, nestedKind); + return new(DeclarationType.Logged, SpecialType.None, nestedKind, null); } token.ThrowIfCancellationRequested(); // If we know we already implement ILogged if (typeSymbol.AllInterfaces.Where(x => x.ToDisplayString() == "Stereologue.ILogged").Any()) { - return (DeclarationType.Logged, nestedKind); + return new(DeclarationType.Logged, SpecialType.None, nestedKind, null); } token.ThrowIfCancellationRequested(); // If we have an UpdateMonologue function @@ -128,7 +132,7 @@ private static (DeclarationType, DeclarationKind)? GetDeclarationType(this IType } if (parameters[0].Type.SpecialType == SpecialType.System_String && parameters[1].Type.ToDisplayString() == "Stereologue.Stereologuer") { - return (DeclarationType.Logged, nestedKind); + return new(DeclarationType.Logged, SpecialType.None, nestedKind, null); } } } @@ -149,55 +153,23 @@ private static (DeclarationType, DeclarationKind)? GetDeclarationType(this IType { if (!attributeInfo.UseProtobuf) { - return (DeclarationType.Struct, nestedKind); + return new(DeclarationType.Struct, SpecialType.None, nestedKind, typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); } } else if (interfaceName == protobufName) { if (attributeInfo.UseProtobuf) { - // TODO disallow arrays of protobuf types - return (DeclarationType.Protobuf, nestedKind); + return new(DeclarationType.Protobuf, SpecialType.None, nestedKind, typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); } } } - // Special case non nested and nullables - if (nestedKind == DeclarationKind.None || nestedKind == DeclarationKind.NullableReferenceType || nestedKind == DeclarationKind.NullableValueType) - { - return (fullTypeName switch - { - "System.Single" => DeclarationType.Float, - "System.Double" => DeclarationType.Double, - "System.Byte" => DeclarationType.Integer, - "System.SByte" => DeclarationType.Integer, - "System.Int16" => DeclarationType.Integer, - "System.UInt16" => DeclarationType.Integer, - "System.Int32" => DeclarationType.Integer, - "System.UInt32" => DeclarationType.Integer, - "System.Int64" => DeclarationType.Integer, - "System.UInt64" => DeclarationType.ULong, - "System.Boolean" => DeclarationType.Boolean, - "System.Char" => DeclarationType.Char, - "System.String" => DeclarationType.String, - _ => DeclarationType.None - }, nestedKind); - } - - - return (fullTypeName switch - { - "System.Single" => DeclarationType.Float, - "System.Double" => DeclarationType.Double, - "System.Byte" => DeclarationType.Raw, - "System.Int64" => DeclarationType.Integer, - "System.Boolean" => DeclarationType.Boolean, - "System.String" => DeclarationType.String, - _ => DeclarationType.None - }, nestedKind); + // We get here by attempting to log a type we have no clue about + return new(DeclarationType.None, SpecialType.None, DeclarationKind.None, null); } - public static LoggableMember? ToLoggableMember(this ISymbol member, CancellationToken token, out DiagnosticInfo? diagnostic) + public static LoggableMember? ToLoggableMember(this ISymbol member, CancellationToken token) { var attributes = member.GetAttributes(); foreach (AttributeData attribute in attributes) @@ -231,12 +203,10 @@ private static (DeclarationType, DeclarationKind)? GetDeclarationType(this IType { if (method.ReturnsVoid) { - diagnostic = DiagnosticInfo.Create(GeneratorDiagnostics.LoggedMethodDoesntReturnVoid, null, [method.Name]); return null; } if (!method.Parameters.IsEmpty) { - diagnostic = DiagnosticInfo.Create(GeneratorDiagnostics.LoggedMethodTakesArguments, null, [method.Name]); return null; } logType = method.ReturnType; @@ -244,7 +214,6 @@ private static (DeclarationType, DeclarationKind)? GetDeclarationType(this IType } else { - diagnostic = DiagnosticInfo.Create(GeneratorDiagnostics.LoggedMemberTypeNotSupported, null, [member.Name]); return null; } token.ThrowIfCancellationRequested(); @@ -253,15 +222,11 @@ private static (DeclarationType, DeclarationKind)? GetDeclarationType(this IType token.ThrowIfCancellationRequested(); if (declType is null) { - // TODO change this to unsupported type - diagnostic = DiagnosticInfo.Create(GeneratorDiagnostics.GeneratedTypeIsInterface, null, null); return null; } - diagnostic = null; - return new LoggableMember(member.Name, memberType, declType.Value.Item1, declType.Value.Item2, attributeInfo); + return new LoggableMember(member.Name, memberType, declType, attributeInfo); } - diagnostic = null; return null; } } diff --git a/sourcegeneration/StereologueSourceGenerator/LoggableType.cs b/sourcegeneration/StereologueSourceGenerator/LoggableType.cs index a5c03aad..99bcaad5 100644 --- a/sourcegeneration/StereologueSourceGenerator/LoggableType.cs +++ b/sourcegeneration/StereologueSourceGenerator/LoggableType.cs @@ -1,70 +1,24 @@ using System.Collections.Immutable; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace Stereologue.SourceGenerator; -// Contains what type of type declaration a loggable type is -[Flags] -internal enum TypeDeclType -{ - None = 0x0, - Class = 0x1, - Struct = 0x2, - Interface = 0x4, - Record = 0x8, - Readonly = 0x10, - Ref = 0x20, -} +internal record TypeDeclType(TypeKind TypeKind, bool IsReadOnly, bool IsRefLikeType, bool IsRecord); // Contains all information on a loggable type internal record LoggableType(TypeDeclType TypeDeclType, string FileName, string TypeName, string? TypeNamespace, EquatableArray LoggableMembers); -internal record LoggableTypeDiagnostics(LoggableType? LoggableType, EquatableArray Diagnostics); - internal static class LoggableTypeExtensions { - public static TypeDeclType GetTypeDeclType(this INamedTypeSymbol symbol, CancellationToken token) + public static TypeDeclType GetTypeDeclType(this INamedTypeSymbol symbol) { - var declType = symbol.TypeKind switch - { - TypeKind.Class => TypeDeclType.Class, - TypeKind.Struct => TypeDeclType.Struct, - TypeKind.Interface => TypeDeclType.Interface, - _ => TypeDeclType.None - }; - - token.ThrowIfCancellationRequested(); - if (declType == TypeDeclType.None) - { - return declType; - } - token.ThrowIfCancellationRequested(); - - if (symbol.IsReadOnly) - { - declType |= TypeDeclType.Readonly; - } - token.ThrowIfCancellationRequested(); - - if (symbol.IsRefLikeType) - { - declType |= TypeDeclType.Ref; - } - token.ThrowIfCancellationRequested(); - - if (symbol.IsRecord) - { - declType |= TypeDeclType.Record; - } - - return declType; + return new TypeDeclType(symbol.TypeKind, symbol.IsReadOnly, symbol.IsRefLikeType, symbol.IsRecord); } - public static LoggableTypeDiagnostics? GetLoggableType(this GeneratorAttributeSyntaxContext context, CancellationToken token) + public static LoggableType? GetLoggableType(this GeneratorAttributeSyntaxContext context, CancellationToken token) { if (context.SemanticModel.GetDeclaredSymbol(context.TargetNode) is not INamedTypeSymbol classSymbol) { @@ -72,24 +26,8 @@ public static TypeDeclType GetTypeDeclType(this INamedTypeSymbol symbol, Cancell } token.ThrowIfCancellationRequested(); - var diagnosticList = ImmutableArray.CreateBuilder(); - - var diagnostic = GetDiagnosticIfInvalidClassForGeneration((TypeDeclarationSyntax)context.TargetNode, classSymbol); + var typeDeclType = classSymbol.GetTypeDeclType(); token.ThrowIfCancellationRequested(); - if (diagnostic is { } ds) - { - diagnosticList.Add(ds); - return new(null, diagnosticList.ToImmutable()); - } - - var typeDeclType = classSymbol.GetTypeDeclType(token); - token.ThrowIfCancellationRequested(); - if (typeDeclType == TypeDeclType.None) - { - // TODO better diagnostic - diagnosticList.Add(DiagnosticInfo.Create(GeneratorDiagnostics.GeneratedTypeIsInterface, null, null)); - return new(null, diagnosticList.ToImmutable()); - } var classMembers = classSymbol.GetMembers(); token.ThrowIfCancellationRequested(); @@ -100,51 +38,26 @@ public static TypeDeclType GetTypeDeclType(this INamedTypeSymbol symbol, Cancell { token.ThrowIfCancellationRequested(); - var loggableMember = member.ToLoggableMember(token, out diagnostic); + var loggableMember = member.ToLoggableMember(token); token.ThrowIfCancellationRequested(); if (loggableMember is null) { - if (diagnostic is not null) - { - diagnosticList.Add(diagnostic.Value); - } continue; } loggableMembers.Add(loggableMember); } - var displayFormat = new SymbolDisplayFormat( - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance); - - var nameString = classSymbol.ToDisplayString(displayFormat); + var nameString = classSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); token.ThrowIfCancellationRequested(); - var ns = classSymbol.ContainingNamespace?.ToDisplayString(); + var nspace = classSymbol.ContainingNamespace is { IsGlobalNamespace: false } ns ? ns.ToDisplayString() : null; token.ThrowIfCancellationRequested(); var fmt = new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.None); - var loggableType = new LoggableType(typeDeclType, $"{classSymbol.ContainingNamespace}{classSymbol.ToDisplayString(fmt)}{classSymbol.MetadataName}", nameString, ns, loggableMembers.ToImmutable()); - - return new(loggableType, diagnosticList.ToImmutable()); - } - - private static DiagnosticInfo? GetDiagnosticIfInvalidClassForGeneration(TypeDeclarationSyntax syntax, ITypeSymbol symbol) - { - // Ensure class is partial - if (!syntax.IsInPartialContext(out var nonPartialIdentifier)) - { - return DiagnosticInfo.Create(GeneratorDiagnostics.GeneratedTypeNotPartial, syntax.Identifier.GetLocation(), [symbol.Name, nonPartialIdentifier]); - } - - // Ensure implementation isn't interface - if (symbol.TypeKind == TypeKind.Interface) - { - return DiagnosticInfo.Create(GeneratorDiagnostics.GeneratedTypeIsInterface, syntax.Identifier.GetLocation(), [symbol.Name]); - } + var loggableType = new LoggableType(typeDeclType, $"{nspace}{classSymbol.ToDisplayString(fmt)}{classSymbol.MetadataName}", nameString, nspace, loggableMembers.ToImmutable()); - return null; + return loggableType; } private static void ConstructCall(LoggableMember data, StringBuilder builder, SourceProductionContext context) @@ -156,91 +69,104 @@ private static void ConstructCall(LoggableMember data, StringBuilder builder, So MemberType.Field => data.Name, MemberType.Property => data.Name, MemberType.Method => $"{data.Name}()", - _ => "UNKNOWN" + _ => "Unknown member type" }; var path = string.IsNullOrWhiteSpace(data.AttributeInfo.Path) ? data.Name : data.AttributeInfo.Path; - if (data.LoggedType == DeclarationType.Logged) + if (data.MemberDeclaration.LoggedType == DeclarationType.Logged) { return; } - if (data.LoggedType == DeclarationType.Struct) - { - return; - } + string logMethod; - if (data.LoggedType == DeclarationType.Protobuf) + if (data.MemberDeclaration.LoggedType == DeclarationType.Struct) { - if (data.LoggedKind != DeclarationKind.None && data.LoggedKind != DeclarationKind.NullableValueType && data.LoggedKind != DeclarationKind.NullableReferenceType) + if (data.MemberDeclaration.LoggedKind != DeclarationKind.None && data.MemberDeclaration.LoggedKind != DeclarationKind.NullableValueType && data.MemberDeclaration.LoggedKind != DeclarationKind.NullableReferenceType) { - builder.Append("Cannot log an array of protobufs"); + // We're an array + logMethod = $"LogStructArray<{data.MemberDeclaration.FQN}>"; } - if (data.LoggedKind == DeclarationKind.NullableValueType) + else + { + logMethod = $"LogStruct<{data.MemberDeclaration.FQN}>"; + } + if (data.MemberDeclaration.LoggedKind == DeclarationKind.NullableValueType) { getOperation = $"{getOperation}.GetValueOrDefault()"; } - builder.Append("logger.LogProto($\"{path}/"); - builder.Append(path); - builder.Append("\", "); - builder.Append(data.AttributeInfo.LogType); - builder.Append(", "); - builder.Append(getOperation); - builder.Append(", "); - builder.Append(data.AttributeInfo.LogLevel); - builder.Append(");"); - return; } - string logMethod; + else if (data.MemberDeclaration.LoggedType == DeclarationType.Protobuf) + { - if (data.LoggedKind == DeclarationKind.None || data.LoggedKind == DeclarationKind.NullableReferenceType || data.LoggedKind == DeclarationKind.NullableValueType) + if (data.MemberDeclaration.LoggedKind != DeclarationKind.None && data.MemberDeclaration.LoggedKind != DeclarationKind.NullableValueType && data.MemberDeclaration.LoggedKind != DeclarationKind.NullableReferenceType) + { + logMethod = "Cannot log an array of protobufs"; + } + else + { + logMethod = $"LogProto<{data.MemberDeclaration.FQN}>"; + } + if (data.MemberDeclaration.LoggedKind == DeclarationKind.NullableValueType) + { + getOperation = $"{getOperation}.GetValueOrDefault()"; + } + } + else if (data.MemberDeclaration.LoggedKind == DeclarationKind.None || data.MemberDeclaration.LoggedKind == DeclarationKind.NullableReferenceType || data.MemberDeclaration.LoggedKind == DeclarationKind.NullableValueType) { - if (data.LoggedType == DeclarationType.String) + // We're not an array. We're either Nullable or a plain type + if (data.MemberDeclaration.SpecialType == SpecialType.System_String) { getOperation = $"{getOperation}.AsSpan()"; } - else if (data.LoggedKind == DeclarationKind.NullableValueType) + else if (data.MemberDeclaration.LoggedKind == DeclarationKind.NullableValueType) { getOperation = $"{getOperation}.GetValueOrDefault()"; } - if (data.LoggedType == DeclarationType.ULong) + if (data.MemberDeclaration.SpecialType == SpecialType.System_UInt64 || data.MemberDeclaration.SpecialType == SpecialType.System_IntPtr || data.MemberDeclaration.SpecialType == SpecialType.System_UIntPtr) { getOperation = $"(long){getOperation}"; } - logMethod = data.LoggedType switch + logMethod = data.MemberDeclaration.SpecialType switch { - DeclarationType.Struct => "LogStruct", - DeclarationType.Protobuf => "LogProto", - DeclarationType.Char => "LogChar", - DeclarationType.String => "LogString", - DeclarationType.Boolean => "LogBoolean", - DeclarationType.Float => "LogFloat", - DeclarationType.Double => "LogDouble", - DeclarationType.Integer => "LogInteger", - DeclarationType.ULong => "LogInteger", - _ => $"Unknown Type: {data.LoggedType}" + SpecialType.System_Char => "LogChar", + SpecialType.System_String => "LogString", + SpecialType.System_Boolean => "LogBoolean", + SpecialType.System_Single => "LogFloat", + SpecialType.System_Double => "LogDouble", + SpecialType.System_Byte => "LogInteger", + SpecialType.System_SByte => "LogInteger", + SpecialType.System_Int16 => "LogInteger", + SpecialType.System_UInt16 => "LogInteger", + SpecialType.System_Int32 => "LogInteger", + SpecialType.System_UInt32 => "LogInteger", + SpecialType.System_Int64 => "LogInteger", + SpecialType.System_UInt64 => "LogInteger", + SpecialType.System_IntPtr => "LogInteger", + SpecialType.System_UIntPtr => "LogInteger", + _ => $"Unknown Type: {data.MemberDeclaration}" }; } else { // We're array of a basic type - if (data.LoggedKind != DeclarationKind.ReadOnlySpan && data.LoggedKind != DeclarationKind.Span) + if (data.MemberDeclaration.LoggedKind != DeclarationKind.ReadOnlySpan && data.MemberDeclaration.LoggedKind != DeclarationKind.Span) { getOperation = $"{getOperation}.AsSpan()"; } - logMethod = data.LoggedType switch + logMethod = data.MemberDeclaration.SpecialType switch { - DeclarationType.String => "LogStringArray", - DeclarationType.Boolean => "LogBooleanArray", - DeclarationType.Float => "LogFloatArray", - DeclarationType.Double => "LogDoubleArray", - DeclarationType.Integer => "LogIntegerArray", - DeclarationType.Raw => "LogRaw", - _ => $"Unknown Array: {data.LoggedType}" + SpecialType.System_String => "LogStringArray", + SpecialType.System_Boolean => "LogBooleanArray", + SpecialType.System_Single => "LogFloatArray", + SpecialType.System_Double => "LogDoubleArray", + SpecialType.System_Byte => "LogRaw", + SpecialType.System_Int64 => "LogIntegerArray", + _ => $"Unknown Array: {data.MemberDeclaration}" }; } @@ -255,100 +181,43 @@ private static void ConstructCall(LoggableMember data, StringBuilder builder, So builder.Append(", "); builder.Append(data.AttributeInfo.LogLevel); builder.Append(");"); - - - // getOperation = data.LoggedModifiers switch - // { - // DeclarationModifiers.AsSpan => $"{getOperation}.AsSpan()", - // DeclarationModifiers.LongCast => $"(long){getOperation}", - // _ => getOperation - // }; - - // - - // if (data.LoggedType == DeclarationType.Logged) - // { - // // TODO check log type to see if we should actually do this - // // TODO arrays of loggables - // builder.Append(getOperation); - // if (data.LoggedModifiers == DeclarationModifiers.AllowNullConditionalOperator) - // { - // builder.Append("?"); - // } - // builder.Append(".UpdateStereologue($\"{path}/"); - // builder.Append(path); - // builder.Append("\", logger);"); - // return; - // } - - // var logCall = data.LoggedType switch - // { - // DeclarationType.Struct => "LogStruct", - // DeclarationType.StructArray => "LogStructArray", - // DeclarationType.Protobuf => "LogProto", - // DeclarationType.Char => "LogChar", - // DeclarationType.String => "LogString", - // DeclarationType.StringArray => "LogStringArray", - // DeclarationType.Boolean => "LogBoolean", - // DeclarationType.BooleanArray => "LogBooleanArray", - // DeclarationType.Float => "LogFloat", - // DeclarationType.FloatArray => "LogFloatArray", - // DeclarationType.Double => "LogDouble", - // DeclarationType.DoubleArray => "LogDoubleArray", - // DeclarationType.Integer => "LogInteger", - // DeclarationType.IntegerArray => "LogIntegerArray", - // DeclarationType.Raw => "LogRaw", - // _ => "UNLOGGABLE_TYPE" - // }; - - // builder.Append("logger."); - // builder.Append(logCall); - // builder.Append("($\"{path}/"); - // builder.Append(path); - // builder.Append("\", "); - // builder.Append(data.AttributeInfo.LogType); - // builder.Append(", "); - // builder.Append(getOperation); - // builder.Append(", "); - // builder.Append(data.AttributeInfo.LogLevel); - // builder.Append(");"); } public static void AddClassDeclaration(LoggableType type, StringBuilder builder) { - if ((type.TypeDeclType & TypeDeclType.Readonly) != 0) + if (type.TypeDeclType.IsReadOnly) { builder.Append("readonly "); } - if ((type.TypeDeclType & TypeDeclType.Ref) != 0) + if (type.TypeDeclType.IsRefLikeType) { builder.Append("ref "); } builder.Append("partial "); - if ((type.TypeDeclType & TypeDeclType.Record) != 0) + if (type.TypeDeclType.IsRecord) { builder.Append("record "); } - if ((type.TypeDeclType & TypeDeclType.Class) != 0) + if (type.TypeDeclType.TypeKind == TypeKind.Class) { builder.Append("class "); } - else if ((type.TypeDeclType & TypeDeclType.Struct) != 0) + else if (type.TypeDeclType.TypeKind == TypeKind.Struct) { builder.Append("struct "); } - else if ((type.TypeDeclType & TypeDeclType.Interface) != 0) + else if (type.TypeDeclType.TypeKind == TypeKind.Interface) { builder.Append("interface "); } builder.Append(type.TypeName); - if ((type.TypeDeclType & TypeDeclType.Ref) != 0) + if (type.TypeDeclType.IsRefLikeType) { builder.AppendLine(); } @@ -358,17 +227,10 @@ public static void AddClassDeclaration(LoggableType type, StringBuilder builder) } } - public static void ExecuteSourceGeneration(this LoggableTypeDiagnostics? typeDiagnostics, SourceProductionContext context) + public static void ExecuteSourceGeneration(this LoggableType? maybeType, SourceProductionContext context) { - if (typeDiagnostics?.Diagnostics is { } diagnostics) - { - foreach (var diagnostic in diagnostics) - { - context.ReportDiagnostic(diagnostic.CreateDiagnostic()); - } - } - if (typeDiagnostics?.LoggableType is { } loggableType) + if (maybeType is { } loggableType) { StringBuilder builder = new StringBuilder(); if (loggableType.TypeNamespace is not null) diff --git a/src/thirdparty/Stereologue/Stereologuer.cs b/src/thirdparty/Stereologue/Stereologuer.cs index 82ff91c8..6f48497e 100644 --- a/src/thirdparty/Stereologue/Stereologuer.cs +++ b/src/thirdparty/Stereologue/Stereologuer.cs @@ -51,7 +51,6 @@ private record struct TypedLogs(TNT? topic, TDataLog? logEntry) w private readonly Dictionary> doubleArrayLogs = []; private readonly Dictionary> stringArrayLogs = []; private readonly Dictionary> structArrayLogs = []; - private readonly Dictionary> protobufArrayLogs = []; private readonly Dictionary> rawLogs = []; public void LogBoolean(string path, LogType logType, bool value, LogLevel logLevel = LogLevel.Default) @@ -113,6 +112,27 @@ public void LogStruct(string path, LogType logType, in T value, LogLevel logL } } + public void LogStructArray(string path, LogType logType, ReadOnlySpan value, LogLevel logLevel = LogLevel.Default) where T : IStructSerializable + { + ref var logs = ref CheckDoLog(path, ref logType, logLevel, structArrayLogs); + if (Unsafe.IsNullRef(ref logs)) + { + return; + } + if (logType.HasFlag(LogType.Nt)) + { + logs.topic ??= ntInstance.GetStructArrayTopic(path).Publish(PubSubOptions.None); + IStructArrayPublisher tl = (IStructArrayPublisher)logs.topic; + tl.Set(value); + } + if (logType.HasFlag(LogType.File)) + { + logs.logEntry ??= new StructArrayLogEntry(log, path); + StructArrayLogEntry tl = (StructArrayLogEntry)logs.logEntry; + tl.Append(value); + } + } + public void LogProto(string path, LogType logType, in T value, LogLevel logLevel = LogLevel.Default) where T : IProtobufSerializable { ref var logs = ref CheckDoLog(path, ref logType, logLevel, protobufLogs); diff --git a/src/wpiutil/Logging/StructArrayLogEntry.cs b/src/wpiutil/Logging/StructArrayLogEntry.cs index 6fee4a6e..6da80c9c 100644 --- a/src/wpiutil/Logging/StructArrayLogEntry.cs +++ b/src/wpiutil/Logging/StructArrayLogEntry.cs @@ -8,20 +8,10 @@ public sealed class StructArrayLogEntry : DataLogEntry where T : IStructSeria private StructBuffer m_storage; private readonly object m_lockObject = new(); - private StructArrayLogEntry(DataLog log, string name, IStruct value, string metadata, long timestamp) : base(log, name, $"{value.TypeString}[]", metadata, timestamp) + public StructArrayLogEntry(DataLog log, string name, string metadata = "", long timestamp = 0) : base(log, name, $"{T.Struct.TypeString}[]", metadata, timestamp) { m_storage = new(); - log.AddSchema(value, timestamp); - } - - public StructArrayLogEntry Create(DataLog log, string name, IStruct value, string metadata = "", long timestamp = 0) - { - return new StructArrayLogEntry(log, name, value, metadata, timestamp); - } - - public StructArrayLogEntry Create(DataLog log, string name, string metadata = "", long timestamp = 0) - { - return new StructArrayLogEntry(log, name, T.Struct, metadata, timestamp); + log.AddSchema(T.Struct, timestamp); } public void Reserve(int nelem) diff --git a/test/stereologue.test/TestTree.cs b/test/stereologue.test/TestTree.cs index 00bc1eb6..7be3681c 100644 --- a/test/stereologue.test/TestTree.cs +++ b/test/stereologue.test/TestTree.cs @@ -116,6 +116,14 @@ public partial class GenerateAllKnownTypes [Log] public double doubleVar; [Log] + public IntPtr intptrVar; + [Log] + public UIntPtr uintptrVar; + [Log] + public nint nintVar; + [Log] + public nuint nuintVar; + [Log] public string? stringVar; [Log]