85 lines
3.1 KiB
C#
85 lines
3.1 KiB
C#
using System;
|
|
using System.Text;
|
|
using CeresSharp.Exceptions;
|
|
|
|
namespace CeresSharp.Native;
|
|
|
|
/// <summary>
|
|
/// Helper class for native interop operations.
|
|
/// Provides utilities for error handling, StringBuilder management, and common patterns.
|
|
/// </summary>
|
|
internal static class NativeHelpers
|
|
{
|
|
private const int DefaultErrorMessageCapacity = 256;
|
|
|
|
// Thread-local buffer pool to avoid allocating a new StringBuilder every call
|
|
[ThreadStatic]
|
|
private static StringBuilder? t_errorMessageBuffer;
|
|
|
|
/// <summary>
|
|
/// Gets a reusable StringBuilder for error messages.
|
|
/// Uses thread-local storage to avoid allocation on each native call.
|
|
/// </summary>
|
|
internal static StringBuilder CreateErrorMessageBuffer(int capacity = DefaultErrorMessageCapacity)
|
|
{
|
|
var sb = t_errorMessageBuffer;
|
|
if (sb != null && sb.Capacity >= capacity)
|
|
{
|
|
sb.Clear();
|
|
return sb;
|
|
}
|
|
sb = new StringBuilder(capacity);
|
|
t_errorMessageBuffer = sb;
|
|
return sb;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extracts error message from StringBuilder, returning null if empty.
|
|
/// </summary>
|
|
internal static string? ExtractErrorMessage(StringBuilder sb)
|
|
{
|
|
return sb.Length > 0 ? sb.ToString() : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks error code and throws exception if not successful.
|
|
/// </summary>
|
|
/// <param name="errorCode">The error code to check.</param>
|
|
/// <param name="errorMessage">Optional error message. If null, will be retrieved from native code.</param>
|
|
/// <exception cref="CeresException">Thrown when error code is not Success.</exception>
|
|
internal static void CheckError(CeresErrorCode errorCode, string? errorMessage = null)
|
|
{
|
|
if (errorCode != CeresErrorCode.Success)
|
|
{
|
|
if (errorMessage == null)
|
|
{
|
|
var errorMessagePtr = CeresNative.ceres_wrapper_get_error_message(errorCode);
|
|
errorMessage = errorMessagePtr != IntPtr.Zero
|
|
? System.Runtime.InteropServices.Marshal.PtrToStringAnsi(errorMessagePtr)
|
|
: $"Unknown error code: {errorCode}";
|
|
}
|
|
throw new CeresException(errorCode, errorMessage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Executes a native operation with error handling.
|
|
/// </summary>
|
|
/// <param name="operation">The operation that returns an error code.</param>
|
|
/// <param name="errorMessageBuffer">Optional StringBuilder for error messages.</param>
|
|
/// <exception cref="CeresException">Thrown when the operation fails.</exception>
|
|
internal static void ExecuteWithErrorHandling(
|
|
Func<StringBuilder, CeresErrorCode> operation,
|
|
StringBuilder? errorMessageBuffer = null)
|
|
{
|
|
errorMessageBuffer ??= CreateErrorMessageBuffer();
|
|
var errorCode = operation(errorMessageBuffer);
|
|
if (errorCode != CeresErrorCode.Success)
|
|
{
|
|
var errorMessage = ExtractErrorMessage(errorMessageBuffer);
|
|
throw new CeresException(errorCode, errorMessage);
|
|
}
|
|
}
|
|
}
|
|
|