From b8fe9c53be6015b6b852ae600517e52a215a0bf4 Mon Sep 17 00:00:00 2001 From: Thad House Date: Mon, 19 Feb 2024 14:32:17 -0800 Subject: [PATCH] Add automatic status checker --- codehelp/CodeHelpers/IndentedStringBuilder.cs | 71 +++++ .../StatusCheckGenerator/MethodModel.cs | 242 ++++++++++++++++++ .../StatusCheckGenerator/ParameterModel.cs | 42 +++ .../SourceGenerator/StatusCheckGenerator.cs | 43 ++++ .../StatusCheckGenerator/Strings.cs | 5 + codehelp/CodeHelpers/SyntaxExtensions.cs | 5 + src/cscore/Natives/CsNative.cs | 107 +++++++- src/cscore/StatusValue.cs | 11 + src/cscore/VideoSource.cs | 4 +- src/cscore/cscore.csproj | 1 + src/wpiutil/AutomateStatusCheckAttribute.cs | 9 + test/stereologue.test/TestTree.cs | 26 ++ test/stereologue.test/stereologue.test.csproj | 2 +- 13 files changed, 560 insertions(+), 8 deletions(-) create mode 100644 codehelp/CodeHelpers/IndentedStringBuilder.cs create mode 100644 codehelp/CodeHelpers/StatusCheckGenerator/MethodModel.cs create mode 100644 codehelp/CodeHelpers/StatusCheckGenerator/ParameterModel.cs create mode 100644 codehelp/CodeHelpers/StatusCheckGenerator/SourceGenerator/StatusCheckGenerator.cs create mode 100644 codehelp/CodeHelpers/StatusCheckGenerator/Strings.cs create mode 100644 src/wpiutil/AutomateStatusCheckAttribute.cs diff --git a/codehelp/CodeHelpers/IndentedStringBuilder.cs b/codehelp/CodeHelpers/IndentedStringBuilder.cs new file mode 100644 index 00000000..b67e2538 --- /dev/null +++ b/codehelp/CodeHelpers/IndentedStringBuilder.cs @@ -0,0 +1,71 @@ +using System.Text; + +namespace WPILib.CodeHelpers; + +public class IndentedStringBuilder +{ + private readonly StringBuilder m_builder = new(); + private int m_scopeCount = 0; + + public void StartLine() + { + m_builder.Append(' ', m_scopeCount * 4); + } + + public void Append(string value) + { + m_builder.Append(value); + } + + public void EndLine() + { + m_builder.AppendLine(); + } + + public void AppendFullLine(string line) + { + StartLine(); + Append(line); + EndLine(); + } + + public IndentedScope EnterScope() + { + return new(this); + } + + public void EnterManualScope() + { + AppendFullLine("{"); + m_scopeCount++; + } + + public void ExitManualScope() + { + m_scopeCount--; + AppendFullLine("}"); + } + + public override string ToString() + { + return m_builder.ToString(); + } + + public readonly ref struct IndentedScope + { + private readonly IndentedStringBuilder m_builder; + + public IndentedScope(IndentedStringBuilder builder) + { + m_builder = builder; + builder.AppendFullLine("{"); + m_builder.m_scopeCount++; + } + + public void Dispose() + { + m_builder.m_scopeCount--; + m_builder.AppendFullLine("}"); + } + } +} diff --git a/codehelp/CodeHelpers/StatusCheckGenerator/MethodModel.cs b/codehelp/CodeHelpers/StatusCheckGenerator/MethodModel.cs new file mode 100644 index 00000000..ac4d0d56 --- /dev/null +++ b/codehelp/CodeHelpers/StatusCheckGenerator/MethodModel.cs @@ -0,0 +1,242 @@ +using System.Collections.Immutable; +using System.Text; +using Microsoft.CodeAnalysis; +using WPILib.CodeHelpers.LogGenerator; + +namespace WPILib.CodeHelpers.StatusCheckGenerator; + +internal enum ReturnKind +{ + None, + Value, + Ref +} + +internal record MethodModel(TypeDeclType TypeDeclType, string TypeName, string? TypeNamespace, string MethodDeclaration, string NameForCall, string TypeConstraints, string ReturnType, ReturnKind ReturnKind, bool NeedsUnsafe, EquatableArray Parameters) +{ + public void AddClassDeclaration(IndentedStringBuilder builder) + { + builder.StartLine(); + if (TypeDeclType.IsReadOnly) + { + builder.Append("readonly "); + } + + if (TypeDeclType.IsRefLikeType) + { + builder.Append("ref "); + } + + if (NeedsUnsafe) { + builder.Append("unsafe "); + } + + builder.Append("partial "); + + if (TypeDeclType.IsRecord) + { + builder.Append("record "); + } + + if (TypeDeclType.TypeKind == TypeKind.Class) + { + builder.Append("class "); + } + else if (TypeDeclType.TypeKind == TypeKind.Struct) + { + builder.Append("struct "); + } + else if (TypeDeclType.TypeKind == TypeKind.Interface) + { + builder.Append("interface "); + } + + builder.Append(TypeName); + builder.EndLine(); + } + + public void WriteMethod(IndentedStringBuilder builder) + { + if (TypeNamespace is not null) + { + builder.AppendFullLine($"namespace {TypeNamespace}"); + builder.EnterManualScope(); + } + + { + AddClassDeclaration(builder); + using var classScope = builder.EnterScope(); + WriteMethodDeclaration(builder); + using var methodScope = builder.EnterScope(); + WriteCallString(builder); + WriteStatusCheck(builder); + WriteReturn(builder); + } + if (TypeNamespace is not null) + { + builder.ExitManualScope(); + } + } + + public void WriteMethodDeclaration(IndentedStringBuilder builder) + { + builder.StartLine(); + builder.Append(MethodDeclaration); + builder.Append("("); + bool first = true; + foreach (var parameter in Parameters) + { + if (first) + { + first = false; + } + else + { + builder.Append(", "); + } + builder.Append(parameter.ParameterString); + } + builder.Append(")"); + builder.Append(TypeConstraints); + builder.EndLine(); + } + + public void WriteCallString(IndentedStringBuilder builder) + { + builder.StartLine(); + if (ReturnKind != ReturnKind.None) + { + builder.Append(ReturnType); + builder.Append(" __tmpValue = "); + if (ReturnKind == ReturnKind.Ref) + { + builder.Append("ref "); + } + } + builder.Append(NameForCall); + builder.Append("("); + bool first = true; + foreach (var parameter in Parameters) + { + if (first) + { + first = false; + } + else + { + builder.Append(", "); + } + parameter.WriteCallString(builder); + } + if (!first) + { + builder.Append(", "); + } + builder.Append("out var __tmpStatus);"); + builder.EndLine(); + } + + public void WriteStatusCheck(IndentedStringBuilder builder) + { + builder.AppendFullLine("__tmpStatus.ThrowIfFailed();"); + } + + public void WriteReturn(IndentedStringBuilder builder) + { + if (ReturnKind == ReturnKind.None) + { + return; + } + builder.StartLine(); + builder.Append("return "); + if (ReturnKind == ReturnKind.Ref) + { + builder.Append("ref "); + } + builder.Append("__tmpValue;"); + builder.EndLine(); + } +} + +internal static class MethodModelExtensions +{ + public static MethodModel? GetMethodModel(this IMethodSymbol symbol) + { + var parameters = ImmutableArray.CreateBuilder(symbol.Parameters.Length); + + if (symbol.Parameters.IsEmpty) + { + return null; + } + + if (symbol.Parameters[^1].RefKind != RefKind.Out) + { + return null; + } + + var symbolParameters = symbol.Parameters; + bool needsUnsafe = false; + + for (int i = 0; i < symbolParameters.Length - 1; i++) + { + parameters.Add(symbolParameters[i].GetParameterModel(ref needsUnsafe)); + } + + var methodDeclarationFormat = new SymbolDisplayFormat( + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + memberOptions: SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeModifiers | SymbolDisplayMemberOptions.IncludeAccessibility | SymbolDisplayMemberOptions.IncludeRef + + ); + + var methodDeclaration = symbol.ToDisplayString(methodDeclarationFormat); + + var callDeclarationFormat = new SymbolDisplayFormat( + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + memberOptions: SymbolDisplayMemberOptions.IncludeRef + ); + + var callDeclaration = symbol.ToDisplayString(callDeclarationFormat); + + var constraintsFmt = new SymbolDisplayFormat( + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeConstraints + ); + + var constraints = symbol.ToDisplayString(constraintsFmt).Replace(symbol.Name, ""); + + var returnTypeFmt = new SymbolDisplayFormat( + memberOptions: SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeRef, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces + ); + + var returnType = symbol.ToDisplayString(returnTypeFmt).Replace(symbol.Name, ""); + + if (symbol.ReturnType.RequiresUnsafe()) { + needsUnsafe = true; + } + + ReturnKind retKind; + + if (symbol.RefKind == RefKind.RefReadOnly || symbol.RefKind == RefKind.Ref) + { + retKind = ReturnKind.Ref; + } + else if (symbol.ReturnsVoid) + { + retKind = ReturnKind.None; + returnType = "void"; + } + else + { + retKind = ReturnKind.Value; + } + + var classSymbol = symbol.ContainingType; + + var nameString = classSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); + var nspace = classSymbol.ContainingNamespace is { IsGlobalNamespace: false } ns ? ns.ToDisplayString() : null; + + return new(classSymbol.GetTypeDeclType(), nameString, nspace, methodDeclaration, callDeclaration, constraints, returnType, retKind, needsUnsafe, parameters.ToImmutable()); + } +} diff --git a/codehelp/CodeHelpers/StatusCheckGenerator/ParameterModel.cs b/codehelp/CodeHelpers/StatusCheckGenerator/ParameterModel.cs new file mode 100644 index 00000000..ee36c34d --- /dev/null +++ b/codehelp/CodeHelpers/StatusCheckGenerator/ParameterModel.cs @@ -0,0 +1,42 @@ +using System.Text; +using Microsoft.CodeAnalysis; + +namespace WPILib.CodeHelpers.StatusCheckGenerator; + +public record ParameterModel(string ParameterString, string Name, RefKind RefKind) +{ + public void WriteCallString(IndentedStringBuilder builder) + { + if (RefKind == RefKind.RefReadOnlyParameter) { + builder.Append("in "); + } else if (RefKind == RefKind.Ref) { + builder.Append("ref "); + } else if (RefKind == RefKind.Out) { + builder.Append("out "); + } + builder.Append(Name); + } +} + +internal static class ParameterModelExtensions +{ + public static ParameterModel GetParameterModel(this IParameterSymbol symbol, ref bool needsUnsafe) + { + var fmt = new SymbolDisplayFormat( + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, + parameterOptions: SymbolDisplayParameterOptions.IncludeExtensionThis | + SymbolDisplayParameterOptions.IncludeModifiers | + SymbolDisplayParameterOptions.IncludeType | + SymbolDisplayParameterOptions.IncludeName | + SymbolDisplayParameterOptions.IncludeDefaultValue, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes + ); + + if (symbol.Type.RequiresUnsafe()) { + needsUnsafe = true; + } + + return new(symbol.ToDisplayString(fmt), symbol.Name, symbol.RefKind); + } +} diff --git a/codehelp/CodeHelpers/StatusCheckGenerator/SourceGenerator/StatusCheckGenerator.cs b/codehelp/CodeHelpers/StatusCheckGenerator/SourceGenerator/StatusCheckGenerator.cs new file mode 100644 index 00000000..89e850af --- /dev/null +++ b/codehelp/CodeHelpers/StatusCheckGenerator/SourceGenerator/StatusCheckGenerator.cs @@ -0,0 +1,43 @@ +using System.Collections.Immutable; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; + +namespace WPILib.CodeHelpers.StatusCheckGenerator.SourceGenerator; + +[Generator] +public class StatusCheckGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var attributedTypes = context.SyntaxProvider + .ForAttributeWithMetadataName( + Strings.StatusCheckAttribute, + predicate: static (s, _) => s is MethodDeclarationSyntax, + transform: static (ctx, token) => + { + if (ctx.SemanticModel.GetDeclaredSymbol(ctx.TargetNode) is not IMethodSymbol classSymbol) + { + return null; + } + return classSymbol.GetMethodModel(); + }) + .Where(static m => m is not null); + + var combined = attributedTypes.Collect(); + + context.RegisterSourceOutput(combined, + static (spc, source) => Execute(source, spc)); + } + + private static void Execute(ImmutableArray model, SourceProductionContext context) + { + IndentedStringBuilder builder = new IndentedStringBuilder(); + foreach (var method in model) { + method?.WriteMethod(builder); + } + + context.AddSource("StatusChecks.g.cs", SourceText.From(builder.ToString(), Encoding.UTF8)); + } +} diff --git a/codehelp/CodeHelpers/StatusCheckGenerator/Strings.cs b/codehelp/CodeHelpers/StatusCheckGenerator/Strings.cs new file mode 100644 index 00000000..2234ca10 --- /dev/null +++ b/codehelp/CodeHelpers/StatusCheckGenerator/Strings.cs @@ -0,0 +1,5 @@ +namespace WPILib.CodeHelpers.StatusCheckGenerator; + +public static class Strings { + public const string StatusCheckAttribute = "WPIUtil.AutomateStatusCheckAttribute"; +} diff --git a/codehelp/CodeHelpers/SyntaxExtensions.cs b/codehelp/CodeHelpers/SyntaxExtensions.cs index d4350cab..fef98399 100644 --- a/codehelp/CodeHelpers/SyntaxExtensions.cs +++ b/codehelp/CodeHelpers/SyntaxExtensions.cs @@ -20,4 +20,9 @@ public static bool IsInPartialContext(this TypeDeclarationSyntax syntax, out Syn nonPartialIdentifier = null; return true; } + + public static bool RequiresUnsafe(this ITypeSymbol symbol) + { + return symbol.TypeKind == TypeKind.Pointer || symbol.TypeKind == TypeKind.FunctionPointer; + } } diff --git a/src/cscore/Natives/CsNative.cs b/src/cscore/Natives/CsNative.cs index b6eb17b9..39ff64f6 100644 --- a/src/cscore/Natives/CsNative.cs +++ b/src/cscore/Natives/CsNative.cs @@ -9,45 +9,55 @@ namespace CsCore.Natives; -public static unsafe partial class CsNative +public static partial class CsNative { + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetPropertyKind")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial PropertyKind GetPropertyKind(CsProperty property, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetPropertyKind")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetPropertyName(CsProperty property, [MarshalUsing(typeof(WpiStringMarshaller))] out string name, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int GetProperty(CsProperty property, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetProperty(CsProperty property, int value, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetPropertyMin")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int GetPropertyMin(CsProperty property, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetPropertyMax")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int GetPropertyMax(CsProperty property, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetPropertyStep")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int GetPropertyStep(CsProperty property, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetPropertyDefault")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int GetPropertyDefault(CsProperty property, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetStringProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetStringProperty(CsProperty property, [MarshalUsing(typeof(WpiStringMarshaller))] out string value, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetStringProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetStringProperty(CsProperty property, WpiString value, out StatusValue status); @@ -58,23 +68,28 @@ public static unsafe partial class CsNative [return: MarshalUsing(typeof(WpiStringMarshaller), ElementIndirectionDepth = 1)] public static partial string[] GetEnumPropertyChoices(CsProperty property, out int count, out StatusValue status); + [AutomateStatusCheck] public static string[] GetEnumPropertyChoices(CsProperty property, out StatusValue status) { return GetEnumPropertyChoices(property, out _, out status); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateUsbCameraDev")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource CreateUsbCamera(WpiString name, int dev, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateUsbCameraPath")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource CreateUsbCamera(WpiString name, WpiString path, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateHttpCamera")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource CreateHttpCamera(WpiString name, WpiString url, HttpCameraKind kind, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateHttpCameraMulti")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource CreateHttpCamera(WpiString name, [MarshalUsing(typeof(WpiStringMarshaller), ElementIndirectionDepth = 1)] ReadOnlySpan urls, int count, HttpCameraKind kind, out StatusValue status); @@ -84,40 +99,49 @@ public static CsSource CreateHttpCamera(string name, ReadOnlySpan urls, return CreateHttpCamera(name, urls, urls.Length, kind, out status); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateCvSource")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource CreateCvSource(WpiString name, in VideoMode mode, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSourceKind")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial SourceKind GetSourceKind(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSourceName")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSourceName(CsSource source, [MarshalUsing(typeof(WpiStringMarshaller))] out string name, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSourceDescription")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSourceDescription(CsSource source, [MarshalUsing(typeof(WpiStringMarshaller))] out string description, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSourceLastFrameTime")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial ulong GetSourceLastFrameTime(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceConnectionStrategy")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetSourceConnectionStrategy(CsSource source, ConnectionStrategy strategy, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_IsSourceConnected")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool IsSourceConnected(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_IsSourceEnabled")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool IsSourceEnabled(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSourceProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsProperty GetSourceProperty(CsSource source, WpiString name, out StatusValue status); @@ -127,45 +151,54 @@ public static CsSource CreateHttpCamera(string name, ReadOnlySpan urls, [return: MarshalUsing(typeof(ManagedFreeArrayMarshaller<,>), CountElementName = "count")] public static partial CsProperty[] EnumerateSourceProperties(CsSource source, out int count, out StatusValue status); + [AutomateStatusCheck] public static CsProperty[] EnumerateSourceProperties(CsSource source, out StatusValue status) { return EnumerateSourceProperties(source, out _, out status); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSourceVideoMode")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSourceVideoMode(CsSource source, out VideoMode mode, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceVideoMode")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool SetSourceVideoMode(CsSource source, in VideoMode mode, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceVideoModeDiscrete")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool SetSourceVideoMode(CsSource source, PixelFormat pixelFormat, int width, int height, int fps, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourcePixelFormat")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool SetSourcePixelFormat(CsSource source, PixelFormat pixelFormat, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceResolution")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool SetSourceResolution(CsSource source, int width, int height, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceFPS")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool SetSourceFps(CsSource source, int fps, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceConfigJson")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool SetSourceConfigJson(CsSource source, WpiString config, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSourceConfigJson")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSourceConfigJson(CsSource source, [MarshalUsing(typeof(WpiStringMarshaller))] out string config, out StatusValue status); @@ -175,6 +208,7 @@ public static CsProperty[] EnumerateSourceProperties(CsSource source, out Status [return: MarshalUsing(typeof(ManagedFreeArrayMarshaller<,>), CountElementName = nameof(count))] public static partial VideoMode[] EnumerateSourceVideoModes(CsSource source, out int count, out StatusValue status); + [AutomateStatusCheck] public static VideoMode[] EnumerateSourceVideoModes(CsSource source, out StatusValue status) { return EnumerateSourceVideoModes(source, out status); @@ -185,63 +219,78 @@ public static VideoMode[] EnumerateSourceVideoModes(CsSource source, out StatusV [return: MarshalUsing(typeof(ManagedFreeArrayMarshaller<,>), CountElementName = nameof(count))] public static partial CsSink[] EnumerateSourceSinks(CsSource source, out int count, out StatusValue status); + [AutomateStatusCheck] public static CsSink[] EnumerateSourceSinks(CsSource source, out StatusValue status) { return EnumerateSourceSinks(source, out _, out status); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CopySource")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource CopySource(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_ReleaseSource")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void ReleaseSource(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetCameraBrightness")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetCameraBrightness(CsSource source, int brightness, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetCameraBrightness")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int GetCameraBrightness(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetCameraWhiteBalanceAuto")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetCameraWhiteBalanceAuto(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetCameraWhiteBalanceHoldCurrent")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetCameraWhiteBalanceHoldCurrent(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetCameraWhiteBalanceManual")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetCameraWhiteBalanceManual(CsSource source, int value, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetCameraExposureAuto")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetCameraExposureAuto(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetCameraExposureHoldCurrent")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetCameraExposureHoldCurrent(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetCameraExposureManual")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetCameraExposureManual(CsSource source, int value, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetUsbCameraPath")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetUsbCameraPath(CsSource source, WpiString path, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetUsbCameraPath")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetUsbCameraPath(CsSource source, [MarshalUsing(typeof(WpiStringMarshaller))] out string path, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetUsbCameraInfo")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial UsbCameraInfo GetUsbCameraInfo(CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetHttpCameraKind")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial HttpCameraKind GetHttpCameraKind(CsSource source, out StatusValue status); @@ -250,6 +299,7 @@ public static CsSink[] EnumerateSourceSinks(CsSource source, out StatusValue sta [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetHttpCameraUrls(CsSource source, [MarshalUsing(typeof(WpiStringMarshaller), ElementIndirectionDepth = 1)] ReadOnlySpan urls, int count, out StatusValue status); + [AutomateStatusCheck] public static void SetHttpCameraUrls(CsSource source, ReadOnlySpan urls, out StatusValue status) { SetHttpCameraUrls(source, urls, urls.Length, out status); @@ -261,27 +311,33 @@ public static void SetHttpCameraUrls(CsSource source, ReadOnlySpan urls, [return: MarshalUsing(typeof(WpiStringMarshaller), ElementIndirectionDepth = 1)] public static partial string[] GetHttpCameraUrls(CsSource source, out int count, out StatusValue status); + [AutomateStatusCheck] public static string[] GetHttpCameraUrls(CsSource source, out StatusValue status) { return GetHttpCameraUrls(source, out _, out status); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_NotifySourceError")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void NotifySourceError(CsSource source, WpiString msg, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceConnected")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetSourceConnected(CsSource source, [MarshalAs(UnmanagedType.I4)] bool connected, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceDescription")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetSourceDescription(CsSource source, WpiString description, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateSourceProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsProperty CreateSourceProperty(CsSource source, WpiString name, PropertyKind kind, int minimum, int maximum, int step, int defaultValue, int value, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSourceEnumPropertyChoices")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetSourceEnumPropertyChoices(CsSource source, CsProperty property, [MarshalUsing(typeof(WpiStringMarshaller), ElementIndirectionDepth = 1)] ReadOnlySpan choices, int count, out StatusValue status); @@ -291,30 +347,37 @@ public static void SetSourceEnumPropertyChoices(CsSource source, CsProperty prop SetSourceEnumPropertyChoices(source, property, choices, choices.Length, out status); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateMjpegServer")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSink CreateMjpegServer(WpiString name, WpiString listenAddress, int port, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateCvSink")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSink CreateCvSink(WpiString name, PixelFormat pixelFormat, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateCvSink")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial CsSink CreateCvSinkCallback(WpiString name, PixelFormat pixelFormat, void* data, delegate* unmanaged[Cdecl] processFrame, out StatusValue status); + public static unsafe partial CsSink CreateCvSinkCallback(WpiString name, PixelFormat pixelFormat, void* data, delegate* unmanaged[Cdecl] processFrame, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkKind")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial SinkKind GetSinkKind(CsSink sink, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkName")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSinkName(CsSink sink, [MarshalUsing(typeof(WpiStringMarshaller))] out string name, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkDescription")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSinkDescription(CsSink sink, [MarshalUsing(typeof(WpiStringMarshaller))] out string description, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsProperty GetSinkProperty(CsSink sink, WpiString name, out StatusValue status); @@ -324,68 +387,84 @@ public static void SetSourceEnumPropertyChoices(CsSource source, CsProperty prop [return: MarshalUsing(typeof(ManagedFreeArrayMarshaller<,>), CountElementName = "count")] public static partial CsProperty[] EnumerateSinkProperties(CsSink sink, out int count, out StatusValue status); + [AutomateStatusCheck] public static CsProperty[] EnumerateSinkProperties(CsSink sink, out StatusValue status) { return EnumerateSinkProperties(sink, out _, out status); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSinkSource")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetSinkSource(CsSink sink, CsSource source, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkSourceProperty")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsProperty GetSinkSourceProperty(CsSink sink, WpiString name, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSinkConfigJson")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool SetSinkConfigJson(CsSink sink, WpiString config, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkConfigJson")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSinkConfigJson(CsSink sink, [MarshalUsing(typeof(WpiStringMarshaller))] out string config, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkSource")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource GetSinkSource(CsSink sink, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CopySink")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSink CopySink(CsSink sink, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_ReleaseSink")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSink ReleaseSink(CsSink sink, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetMjpegServerListenAddress")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetMjpegServerListenAddress(CsSink sink, [MarshalUsing(typeof(WpiStringMarshaller))] out string listenAddress, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetMjpegServerPort")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int GetMjpegServerPort(CsSink sink, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSinkDescription")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetSinkDescription(CsSink sink, WpiString description, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetSinkError")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void GetSinkError(CsSink sink, [MarshalUsing(typeof(WpiStringMarshaller))] out string error, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetSinkEnabled")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial int SetSinkEnabled(CsSink sink, [MarshalAs(UnmanagedType.I4)] bool enabled, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateListenerPoller")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsListenerPoller CreateListenerPoller(); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_DestroyListenerPoller")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void DestroyListenerPoller(CsListenerPoller poller); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_AddPolledListener")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsListener AddPolledListener(CsListenerPoller poller, EventKind eventMask, [MarshalAs(UnmanagedType.I4)] bool immediateNotify, out StatusValue status); @@ -410,47 +489,58 @@ public static VideoEvent[] PollListener(CsListenerPoller poller, double timeout, return PollListener(poller, out _, timeout, out timedOut); } + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_FreeEvents")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial void FreeEvents(VideoEventMarshaller.NativeCsEvent* arr, int count); + public static unsafe partial void FreeEvents(VideoEventMarshaller.NativeCsEvent* arr, int count); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CancelPollListener")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void CancelPollListener(CsListenerPoller poller); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_RemoveListener")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void RemoveListener(CsListener listener, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_NotifierDestroyed")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalAs(UnmanagedType.I4)] public static partial bool IsNotifierDestroyed(); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetTelemetryPeriod")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetTelemetryPeriod(double seconds); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetTelemetryElapsedTime")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial double GetTelemetryElapsedTime(); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetTelemetryValue")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial long GetTelemetryValue(CsSource source, TelemetryKind kind, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GetTelemetryAverageValue")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial long GetTelemetryAverageValue(CsSource source, TelemetryKind kind, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetLogger")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial void SetLogger(delegate* unmanaged[Cdecl] func, uint min_level); + public static unsafe partial void SetLogger(delegate* unmanaged[Cdecl] func, uint min_level); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_SetDefaultLogger")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void SetDefaultLogger(uint min_level); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_Shutdown")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void CS_Shutdown(); @@ -460,16 +550,19 @@ public static VideoEvent[] PollListener(CsListenerPoller poller, double timeout, [return: MarshalUsing(typeof(ManagedFreeArrayMarshaller<,>), CountElementName = nameof(count))] public static partial UsbCameraInfo[] EnumerateUsbCameras(out int count, out StatusValue status); + [AutomateStatusCheck] public static UsbCameraInfo[] EnumerateUsbCameras(out StatusValue status) { return EnumerateUsbCameras(out _, out status); } + [LibraryImport("cscore", EntryPoint = "CS_EnumerateSources")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [return: MarshalUsing(typeof(ManagedFreeArrayMarshaller<,>), CountElementName = nameof(count))] public static partial CsSource[] EnumerateSources(out int count, out StatusValue status); + [AutomateStatusCheck] public static CsSource[] EnumerateSources(out StatusValue status) { return EnumerateSources(out _, out status); @@ -480,6 +573,7 @@ public static CsSource[] EnumerateSources(out StatusValue status) [return: MarshalUsing(typeof(ManagedFreeArrayMarshaller<,>), CountElementName = nameof(count))] public static partial CsSink[] EnumerateSinks(out int count, out StatusValue status); + [AutomateStatusCheck] public static CsSink[] EnumerateSinks(out StatusValue status) { return EnumerateSinks(out _, out status); @@ -495,22 +589,27 @@ public static CsSink[] EnumerateSinks(out StatusValue status) [return: MarshalUsing(typeof(WpiStringMarshaller), ElementIndirectionDepth = 1)] public static partial string[] GetNetworkInterfaces(out int count); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GrabRawSinkFrame")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial ulong GrabRawSinkFrame(CsSink sink, RawFrameReader rawImage, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_GrabRawSinkFrameTimeout")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial ulong GrabRawSinkFrame(CsSink sink, RawFrameReader rawImage, double timeout, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateRawSink")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSink CreateRawSink(WpiString name, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_PutRawSourceFrame")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void PutRawSourceFrame(CsSource source, RawFrameWriter rawImage, out StatusValue status); + [AutomateStatusCheck] [LibraryImport("cscore", EntryPoint = "CS_CreateRawSource")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial CsSource CreateRawSource(WpiString name, in VideoMode mode, out StatusValue status); diff --git a/src/cscore/StatusValue.cs b/src/cscore/StatusValue.cs index 2b334eb3..3f5f5eee 100644 --- a/src/cscore/StatusValue.cs +++ b/src/cscore/StatusValue.cs @@ -1,3 +1,5 @@ +using System.Runtime.CompilerServices; + namespace CsCore; public enum StatusValue : int @@ -15,3 +17,12 @@ public enum StatusValue : int TelemetryNotEnabled = -2008, UnsupportedMode = -2009, } + +public static class StatusValueExtensions +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ThrowIfFailed(this StatusValue status) + { + + } +} diff --git a/src/cscore/VideoSource.cs b/src/cscore/VideoSource.cs index 8cd81cea..de500c15 100644 --- a/src/cscore/VideoSource.cs +++ b/src/cscore/VideoSource.cs @@ -102,9 +102,7 @@ public VideoMode VideoMode public bool SetConfigJson(string config) { - var ret = CsNative.SetSourceConfigJson(Handle, config, out var status); - VideoException.ThrowIfFailed(status); - return ret; + return CsNative.SetSourceConfigJson(Handle, config); } public string GetConfigJson() diff --git a/src/cscore/cscore.csproj b/src/cscore/cscore.csproj index e09f3b76..9eb338d0 100644 --- a/src/cscore/cscore.csproj +++ b/src/cscore/cscore.csproj @@ -21,6 +21,7 @@ + diff --git a/src/wpiutil/AutomateStatusCheckAttribute.cs b/src/wpiutil/AutomateStatusCheckAttribute.cs new file mode 100644 index 00000000..e7e78df4 --- /dev/null +++ b/src/wpiutil/AutomateStatusCheckAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace WPIUtil; + +[AttributeUsage(AttributeTargets.Method)] +public sealed class AutomateStatusCheckAttribute : Attribute +{ + +} diff --git a/test/stereologue.test/TestTree.cs b/test/stereologue.test/TestTree.cs index e2bc507d..5331ae32 100644 --- a/test/stereologue.test/TestTree.cs +++ b/test/stereologue.test/TestTree.cs @@ -1,7 +1,15 @@ +using System.Runtime.CompilerServices; using WPIMath.Geometry; +using WPIUtil; namespace Stereologue.Test; +public static class IntExtensions { + public static void ThrowIfFailed(this int x) { + + } +} + [GenerateLog] public partial class GenerateGenericClass { @@ -16,6 +24,24 @@ public partial class GenerateGenericClassConstraint where T : struct { [Log] public int Variable { get; } + + [AutomateStatusCheck] + public static ref readonly int PerformStatusCheck(int x, ref int y, out int z, ref readonly int a, in int b, out int status) where T2 : struct { + z = y; + status = 0; + return ref Unsafe.NullRef(); + } + + [AutomateStatusCheck] + public static void PerformStatusCheck(out int status) { + status = 0; + } + + [AutomateStatusCheck] + public static int PerformStatusCheck(int x, out int status) { + status = 0; + return x; + } } [GenerateLog] diff --git a/test/stereologue.test/stereologue.test.csproj b/test/stereologue.test/stereologue.test.csproj index b56a8b79..55864a83 100644 --- a/test/stereologue.test/stereologue.test.csproj +++ b/test/stereologue.test/stereologue.test.csproj @@ -7,7 +7,7 @@ - false + true