using System.Runtime.InteropServices;
namespace Flyshot.Native.Planning;
///
/// 声明 Rust 原生规划库导出的稳定 C ABI 方法。
///
internal static partial class NativeIcspMethods
{
///
/// 保护原生库句柄首次初始化,避免并发规划重复加载。
///
private static readonly object LibraryLoadLock = new();
///
/// 保存已加载原生库句柄,使 P/Invoke 生命周期覆盖整个进程。
///
private static nint _libraryHandle;
///
/// 保存当前进程已绑定到 P/Invoke 逻辑名称的实际库路径。
///
private static string? _loadedLibraryPath;
///
/// 初始化程序集级 DllImport 解析器,把逻辑库名绑定到显式加载句柄。
///
static NativeIcspMethods()
{
NativeLibrary.SetDllImportResolver(
typeof(NativeIcspMethods).Assembly,
ResolveImportedLibrary);
}
///
/// 使用指定解析器确保原生规划库已加载。
///
/// 负责生成平台路径并加载原生库的解析器。
internal static void EnsureLibraryLoaded(NativePlanningLibraryResolver resolver)
{
ArgumentNullException.ThrowIfNull(resolver);
string requestedPath = resolver.ResolveLibraryPath();
lock (LibraryLoadLock)
{
if (_libraryHandle != nint.Zero)
{
StringComparison comparison = OperatingSystem.IsWindows()
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
if (!string.Equals(_loadedLibraryPath, requestedPath, comparison))
{
throw new NativePlanningException(
$"Rust 原生规划库已绑定到“{_loadedLibraryPath}”,不能在同一进程中改为“{requestedPath}”。",
errorCode: -1008);
}
return;
}
_libraryHandle = resolver.LoadLibrary();
_loadedLibraryPath = requestedPath;
}
}
///
/// 调用 Rust ICSP 入口并返回错误码和结果指针。
///
/// 行优先连续路点数组。
/// 路点数量。
/// 每个路点的关节自由度。
/// 逐关节速度上限。
/// 逐关节加速度上限。
/// 逐关节 jerk 上限。
/// 与 Rust C ABI 对齐的规划选项。
/// 接收 Rust 分配的结果指针。
/// 零表示成功,非零表示固定类别的原生错误。
[LibraryImport(
NativePlanningLibraryResolver.LogicalLibraryName,
EntryPoint = "flyshot_icsp_plan")]
internal static unsafe partial int FlyshotIcspPlan(
double* waypoints,
int waypointCount,
int degreesOfFreedom,
double* velocityLimits,
double* accelerationLimits,
double* jerkLimits,
NativeIcspOptions* options,
out nint result);
///
/// 释放由 Rust 分配的 ICSP 结果对象。
///
/// Rust 返回的结果对象指针;允许为空指针。
[LibraryImport(
NativePlanningLibraryResolver.LogicalLibraryName,
EntryPoint = "flyshot_icsp_result_free")]
internal static partial void FlyshotIcspResultFree(nint result);
///
/// 获取当前线程最近一次 Rust 调用保存的 UTF-8 错误文本。
///
/// 指向线程局部 C 字符串的只读指针。
[LibraryImport(
NativePlanningLibraryResolver.LogicalLibraryName,
EntryPoint = "flyshot_last_error_message")]
internal static partial nint FlyshotLastErrorMessage();
///
/// 将固定逻辑库名解析为已经显式加载的系统句柄。
///
/// P/Invoke 请求的逻辑库名。
/// 发起请求的托管程序集。
/// 调用方提供的可选搜索路径。
/// 逻辑名称匹配时返回已加载句柄,否则返回零交给系统继续解析。
private static nint ResolveImportedLibrary(
string libraryName,
System.Reflection.Assembly assembly,
DllImportSearchPath? searchPath)
{
_ = assembly;
_ = searchPath;
return string.Equals(
libraryName,
NativePlanningLibraryResolver.LogicalLibraryName,
StringComparison.Ordinal)
? _libraryHandle
: nint.Zero;
}
}