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); } } }