# Rust ICSP Native Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 为现有 `ICspPlanner` 增加一套基于 Rust `cdylib` 的原生 ICSP 规划实现,并通过 C ABI + C# P/Invoke 完成可验证的对拍接入,同时不改变当前默认生产路径。 **Architecture:** 新增 `native/flyshot-native-planning` Rust 原生库承载 clamped-zero 三次样条与 ICSP 迭代核心;新增 `src/Flyshot.Native.Planning` 托管互操作项目负责库加载、数组编排、错误转换和结果复制。现有 `Flyshot.Core.Planning.ICspPlanner` 保持不变,`RustIcspPlanner` 仅作为显式新入口并在测试中与托管实现逐项对拍。 **Tech Stack:** Rust `cdylib`、C ABI、.NET 8、`LibraryImport`、`SafeHandle`、xUnit、PowerShell、Cargo --- ### Task 1: 建立原生与托管骨架 **Files:** - Create: `native/flyshot-native-planning/Cargo.toml` - Create: `native/flyshot-native-planning/src/lib.rs` - Create: `native/flyshot-native-planning/src/error.rs` - Create: `native/flyshot-native-planning/src/ffi.rs` - Create: `native/flyshot-native-planning/src/icsp.rs` - Create: `native/flyshot-native-planning/src/spline.rs` - Create: `src/Flyshot.Native.Planning/Flyshot.Native.Planning.csproj` - Create: `src/Flyshot.Native.Planning/NativeIcspMethods.cs` - Create: `src/Flyshot.Native.Planning/NativeIcspSafeHandle.cs` - Create: `src/Flyshot.Native.Planning/NativePlanningException.cs` - Create: `src/Flyshot.Native.Planning/NativePlanningLibraryResolver.cs` - Modify: `FlyshotReplacement.sln` - Modify: `tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj` - [x] **Step 1: 先写托管侧失败测试,锁定缺少原生库时的报错边界** ```csharp [Fact] public void RustIcspPlanner_ThrowsClearError_WhenNativeLibraryIsMissing() { var planner = new RustIcspPlanner( options: NativeIcspPlannerOptions.Default, libraryResolver: new NativePlanningLibraryResolver(_ => "missing-library")); var exception = Assert.Throws(() => planner.Plan(CreateSimpleRequest())); Assert.Contains("missing-library", exception.Message); } ``` - [x] **Step 2: 运行单测确认当前失败** Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter RustIcspPlanner_ThrowsClearError_WhenNativeLibraryIsMissing -v minimal` Expected: FAIL,提示 `RustIcspPlanner` 或互操作类型不存在 - [x] **Step 3: 创建 Rust `cdylib` 和托管互操作项目骨架** ```toml [package] name = "flyshot_planning" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [profile.release] lto = true codegen-units = 1 strip = "symbols" panic = "abort" ``` ```xml net8.0 true ``` - [x] **Step 4: 添加最小库解析与异常包装实现** ```csharp public sealed class NativePlanningException : Exception { public NativePlanningException(string message, int errorCode, Exception? innerException = null) : base(message, innerException) { ErrorCodeValue = errorCode; } public int ErrorCodeValue { get; } } ``` ```csharp public sealed class NativePlanningLibraryResolver { private readonly Func _resolveLibraryPath; } ``` - [x] **Step 5: 重新运行单测,确认错误已变为清晰的原生库缺失异常** Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter RustIcspPlanner_ThrowsClearError_WhenNativeLibraryIsMissing -v minimal` Expected: PASS ### Task 2: 先做样条基础能力 **Files:** - Modify: `native/flyshot-native-planning/src/spline.rs` - Modify: `native/flyshot-native-planning/src/lib.rs` - Create: `native/flyshot-native-planning/tests/spline_tests.rs` - [x] **Step 1: 先写 Rust 失败测试,锁定 clamped-zero 样条边界和值/导数接口** ```rust #[test] fn clamped_zero_spline_hits_waypoints_and_zero_boundary_velocity() { let times = [0.0, 1.0, 2.0, 3.0]; let values = [0.0, 1.0, 0.5, 2.0]; let spline = CubicSpline1D::new_clamped_zero(×, &values).unwrap(); assert_abs_diff_eq!(spline.position(0.0), 0.0, epsilon = 1e-12); assert_abs_diff_eq!(spline.position(3.0), 2.0, epsilon = 1e-12); assert_abs_diff_eq!(spline.velocity(0.0), 0.0, epsilon = 1e-12); assert_abs_diff_eq!(spline.velocity(3.0), 0.0, epsilon = 1e-12); } ``` - [x] **Step 2: 运行 Rust 测试确认失败** Run: `cargo test --manifest-path native/flyshot-native-planning/Cargo.toml spline_tests::clamped_zero_spline_hits_waypoints_and_zero_boundary_velocity -- --exact` Expected: FAIL,提示样条类型或构造函数不存在 - [x] **Step 3: 实现三对角求解、样条系数和每段导数峰值接口** ```rust pub struct CubicSpline1D { knots: Vec, coefficients: Vec<[f64; 4]>, } impl CubicSpline1D { pub fn new_clamped_zero(times: &[f64], values: &[f64]) -> Result { /* ... */ } pub fn position(&self, time: f64) -> f64 { /* ... */ } pub fn velocity(&self, time: f64) -> f64 { /* ... */ } pub fn acceleration(&self, time: f64) -> f64 { /* ... */ } pub fn jerk(&self, time: f64) -> f64 { /* ... */ } pub fn segment_peak_derivatives(&self, segment_index: usize) -> [f64; 3] { /* ... */ } } ``` - [x] **Step 4: 重新运行 Rust 样条测试** Run: `cargo test --manifest-path native/flyshot-native-planning/Cargo.toml spline_tests::clamped_zero_spline_hits_waypoints_and_zero_boundary_velocity -- --exact` Expected: PASS ### Task 3: 实现纯 Rust ICSP 核心 **Files:** - Modify: `native/flyshot-native-planning/src/icsp.rs` - Create: `native/flyshot-native-planning/tests/icsp_tests.rs` - [x] **Step 1: 先写 Rust 失败测试,锁定初始段时长、scale 计算和未收敛路径** ```rust #[test] fn icsp_returns_same_iteration_count_as_managed_baseline_fixture() { let input = test_fixture_three_segment_case(); let result = plan_icsp(&input).unwrap(); assert_eq!(result.iterations, 2); assert_abs_diff_eq!(result.threshold, 0.0, epsilon = 1e-12); } ``` - [x] **Step 2: 运行 Rust ICSP 测试确认失败** Run: `cargo test --manifest-path native/flyshot-native-planning/Cargo.toml icsp_tests::icsp_returns_same_iteration_count_as_managed_baseline_fixture -- --exact` Expected: FAIL,提示 `plan_icsp` 或结果结构不存在 - [x] **Step 3: 实现最小 ICSP 纯算法结构,逐项复刻 C# 收敛语义** ```rust pub struct IcspInput<'a> { pub waypoints: &'a [f64], pub waypoint_count: usize, pub dof: usize, pub velocity_limits: &'a [f64], pub acceleration_limits: &'a [f64], pub jerk_limits: &'a [f64], pub options: IcspOptions, } pub fn plan_icsp(input: &IcspInput<'_>) -> Result { /* ... */ } ``` - [x] **Step 4: 重新运行 Rust ICSP 测试** Run: `cargo test --manifest-path native/flyshot-native-planning/Cargo.toml icsp_tests::icsp_returns_same_iteration_count_as_managed_baseline_fixture -- --exact` Expected: PASS ### Task 4: 接通 C ABI 和托管结果复制 **Files:** - Modify: `native/flyshot-native-planning/src/ffi.rs` - Modify: `native/flyshot-native-planning/src/error.rs` - Modify: `src/Flyshot.Native.Planning/NativeIcspMethods.cs` - Modify: `src/Flyshot.Native.Planning/NativeIcspSafeHandle.cs` - Create: `src/Flyshot.Native.Planning/NativeIcspInteropModels.cs` - Create: `src/Flyshot.Native.Planning/RustIcspPlanner.cs` - Create: `tests/Flyshot.Core.Tests/RustIcspPlannerInteropTests.cs` - [x] **Step 1: 先写托管失败测试,锁定数组布局、结果复制和释放路径** ```csharp [Fact] public void RustIcspPlanner_ReturnsManagedPlannedTrajectory_FromNativeResult() { var planner = CreateRustPlannerAgainstBuiltNativeLibrary(); var result = planner.Plan(CreateSimpleRequest()); Assert.Equal(PlanningMethod.Icsp, result.Method); Assert.Equal(result.PlannedWaypointCount, result.WaypointTimes.Count); } ``` - [x] **Step 2: 运行单测确认失败** Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter RustIcspPlanner_ReturnsManagedPlannedTrajectory_FromNativeResult -v minimal` Expected: FAIL,提示 P/Invoke 签名、结果结构或释放逻辑未实现 - [x] **Step 3: 实现 C ABI 入口、线程局部错误文本和 `SafeHandle` 释放** ```rust #[no_mangle] pub extern "C" fn flyshot_icsp_plan(/* ... */) -> i32 { /* ... */ } #[no_mangle] pub extern "C" fn flyshot_icsp_result_free(result: *mut FlyshotIcspResult) { /* ... */ } #[no_mangle] pub extern "C" fn flyshot_last_error_message() -> *const c_char { /* ... */ } ``` ```csharp [LibraryImport(NativeLibraryName, EntryPoint = "flyshot_icsp_plan")] internal static unsafe partial int FlyshotIcspPlan(/* ... */); ``` - [x] **Step 4: 重新运行托管互操作测试** Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter RustIcspPlanner_ReturnsManagedPlannedTrajectory_FromNativeResult -v minimal` Expected: PASS ### Task 5: 增加 C#/Rust 对拍测试和构建复制脚本 **Files:** - Modify: `tests/Flyshot.Core.Tests/PlanningCompatibilityTests.cs` - Create: `tests/Flyshot.Core.Tests/RustIcspPlannerParityTests.cs` - Create: `build/Copy-NativePlanningArtifacts.ps1` - Modify: `README.md` - [x] **Step 1: 先写失败测试,锁定 C# 与 Rust 在基础样本上的逐项一致** ```csharp [Fact] public void RustIcspPlanner_MatchesManagedIcspPlanner_ForCompatibilityFixture() { var request = CreateCompatibilityRequest(); var managed = new ICspPlanner().Plan(request); var native = CreateRustPlannerAgainstBuiltNativeLibrary().Plan(request); AssertTrajectoryMatches(managed, native, tolerance: 1e-9); } ``` - [x] **Step 2: 运行对拍测试确认失败** Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter RustIcspPlanner_MatchesManagedIcspPlanner_ForCompatibilityFixture -v minimal` Expected: FAIL,提示数值未对齐或原生库复制失败 - [x] **Step 3: 补齐原生库复制脚本、测试输出复制规则和对拍辅助断言** ```powershell param( [string]$Configuration = "Release" ) cargo build --manifest-path native/flyshot-native-planning/Cargo.toml --release Copy-Item native/flyshot-native-planning/target/release/flyshot_planning.dll tests/Flyshot.Core.Tests/bin/$Configuration/net8.0/ -Force ``` - [x] **Step 4: 重新运行对拍测试** Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj --filter RustIcspPlanner_MatchesManagedIcspPlanner_ForCompatibilityFixture -v minimal` Expected: PASS ### Task 6: 解决方案级验证 **Files:** - Modify: `README.md` - Modify: `docs/superpowers/specs/2026-06-22-rust-icsp-native-design.md` - [x] **Step 1: 运行 Rust 全量测试** Run: `cargo test --manifest-path native/flyshot-native-planning/Cargo.toml` Expected: PASS - [ ] **Step 2: 运行 Core 测试** Run: `dotnet test tests/Flyshot.Core.Tests/Flyshot.Core.Tests.csproj -v minimal` Expected: PASS 当前验证:新增 Rust 相关测试全部通过;Core 全套仍保留实施前已存在的两项 `FlyshotExecutionSendSequenceBuilder` speed-ratio 失败,本计划未修改该行为。 - [x] **Step 3: 运行解决方案构建** Run: `dotnet build FlyshotReplacement.sln -v minimal` Expected: PASS - [x] **Step 4: 更新文档,记录本地构建、库复制和当前上线边界** ```markdown - Rust 规划器当前仅显式使用,不替换默认 `ICspPlanner` - Windows 需要 `flyshot_planning.dll` - Linux 需要 `libflyshot_planning.so` ```