using System;
using System.Text;
using CeresSharp.Exceptions;
namespace CeresSharp.Native;
///
/// Helper class for native interop operations.
/// Provides utilities for error handling, StringBuilder management, and common patterns.
///
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;
///
/// Gets a reusable StringBuilder for error messages.
/// Uses thread-local storage to avoid allocation on each native call.
///
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;
}
///
/// Extracts error message from StringBuilder, returning null if empty.
///
internal static string? ExtractErrorMessage(StringBuilder sb)
{
return sb.Length > 0 ? sb.ToString() : null;
}
///
/// Checks error code and throws exception if not successful.
///
/// The error code to check.
/// Optional error message. If null, will be retrieved from native code.
/// Thrown when error code is not Success.
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);
}
}
///
/// Executes a native operation with error handling.
///
/// The operation that returns an error code.
/// Optional StringBuilder for error messages.
/// Thrown when the operation fails.
internal static void ExecuteWithErrorHandling(
Func operation,
StringBuilder? errorMessageBuffer = null)
{
errorMessageBuffer ??= CreateErrorMessageBuffer();
var errorCode = operation(errorMessageBuffer);
if (errorCode != CeresErrorCode.Success)
{
var errorMessage = ExtractErrorMessage(errorMessageBuffer);
throw new CeresException(errorCode, errorMessage);
}
}
}