48 lines
2.0 KiB
Markdown
48 lines
2.0 KiB
Markdown
---
|
|
epic: 1
|
|
story: 1.5
|
|
title: "C FFI Layer (for Swift)"
|
|
status: draft
|
|
---
|
|
|
|
## Epic 1 — Core Calculation Engine (Rust Crate)
|
|
**Goal:** Build `calcpad-engine` as a standalone Rust crate that powers all platforms. This is the foundation.
|
|
|
|
### Story 1.5: C FFI Layer (for Swift)
|
|
|
|
As a macOS/iOS developer integrating CalcPad,
|
|
I want a stable C ABI with explicit memory ownership and no panics crossing the FFI boundary,
|
|
So that Swift can safely call into the Rust engine without undefined behavior.
|
|
|
|
**Acceptance Criteria:**
|
|
|
|
**Given** a Swift caller invoking `calcpad_eval_line` with a C string input
|
|
**When** the function executes
|
|
**Then** it returns a pointer to a `CalcResult` struct (or JSON-serialized string) allocated on the Rust heap
|
|
**And** the caller is responsible for freeing the result via `calcpad_free_result`
|
|
|
|
**Given** a Swift caller invoking `calcpad_eval_sheet` with multiple lines
|
|
**When** the function executes
|
|
**Then** it returns an array of results corresponding to each line
|
|
**And** variable assignments on earlier lines are visible to later lines
|
|
|
|
**Given** an expression that would cause a Rust panic (e.g., internal bug)
|
|
**When** the FFI function is called
|
|
**Then** `catch_unwind` intercepts the panic
|
|
**And** an error result is returned instead of unwinding into Swift
|
|
|
|
**Given** the FFI result is serialized as JSON
|
|
**When** the result crosses the FFI boundary
|
|
**Then** the JSON schema is versioned so Swift can handle backward-compatible changes
|
|
**And** the JSON includes result type, display value, raw value, and any error information
|
|
|
|
**Given** a `CalcResult` pointer returned from `calcpad_eval_line`
|
|
**When** the Swift caller calls `calcpad_free_result` with that pointer
|
|
**Then** the Rust allocator deallocates the memory
|
|
**And** no double-free or use-after-free is possible from correct usage
|
|
|
|
**Given** a null or invalid pointer passed to `calcpad_free_result`
|
|
**When** the function is called
|
|
**Then** it safely handles the null/invalid input without crashing
|
|
**And** no undefined behavior occurs
|