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