ballistics-engine 0.49.0

High-performance ballistics trajectory engine with professional physics
Documentation
/* ballistics-engine JSON command bridge — C ABI.
 *
 * One request/response exchange per call. The request is a UTF-8 JSON envelope:
 *
 *   { "api_version": 1, "command": "meta.capabilities" }
 *   { "api_version": 1, "command": "solve", "request": { ...solve-json v1... } }
 *
 * The response is always a UTF-8 JSON envelope. On success:
 *
 *   { "ok": true, "api_version": 1, "engine_version": "...",
 *     "command": "...", "result": { ... } }
 *
 * On ANY failure (invalid UTF-8, malformed JSON, unknown command, command
 * failure, internal error) the failure is reported IN-BAND:
 *
 *   { "ok": false, "api_version": 1, "engine_version": "...",
 *     "error": { "code": "...", "message": "...", "details": { ... } } }
 *
 * Branch on "ok" and "error"."code" rather than on which fields are present:
 * a request refused before it reaches the bridge — one whose bytes are not
 * UTF-8, or a NULL pointer — is answered by this ABI layer with the minimal
 * shape, "ok"/"api_version"/"error", and carries no "engine_version".
 *
 * "details" appears only when "code" is "command_failed", and not always then.
 * Its shape depends on the command:
 *
 *   - "solve" and "atmosphere.density_altitude": the command's whole solve-json
 *     error envelope, so the code to branch on is error.details.error.code:
 *
 *       "details": { "schema_version": 1, "status": "error",
 *                    "error": { "code": "invalid_value", "message": "...",
 *                               "path": "$.atmosphere.latitude_rad",
 *                               "line": null, "column": null } }
 *
 *     "path" is a string, or JSON null when no one field is at fault (as with
 *     "solve_failed"). "line" and "column" are null: malformed JSON fails the
 *     envelope itself first, as "invalid_json". The outer "message" is
 *     "solve request rejected" when the solve-json decoder refused the
 *     document, "solve failed" when the solve service refused or could not
 *     finish it, and "atmosphere.density_altitude request rejected" for every
 *     refusal of that command.
 *   - "reticle.describe", "reticle.hold", "reticle.holds", "reticle.import",
 *     "true.dsf", "true.plan", "true.dial_plan" and "profile.export_a7p": a
 *     flat object with a machine-readable "reason", plus the offending values
 *     when the error has any.
 *   - Every other command: no "details"; the reason is in "message" alone.
 *
 * Messages are text for a person; branch on codes. Per command, with a Kotlin
 * unwrap: docs/ANDROID_JNI_BRIDGE.md, "Reading a failure".
 *
 * Contract:
 *   - The calls NEVER return NULL and NEVER throw/abort; check "ok" in the JSON.
 *   - The caller owns the input buffer; the engine does not retain it.
 *   - Every returned pointer must be released exactly once with
 *     ballistics_bridge_free(). Freeing NULL is a no-op.
 *   - Calls are thread-safe and independent; there is no shared mutable state.
 *   - Requests larger than 1 MiB are rejected with code "resource_limit".
 *   - Feature-detect with the "meta.capabilities" command instead of assuming a
 *     command list; builds differ (e.g. "pdf", "profile-import").
 *
 * ANDROID / JNI: call ballistics_bridge_call_n with the bytes of a Kotlin
 * String.toByteArray(Charsets.UTF_8), and return the response as a jbyteArray.
 * JNI's own string conversions — GetStringUTFChars AND GetStringUTFRegion —
 * produce MODIFIED UTF-8, which this ABI refuses as invalid UTF-8 the first
 * time a user types a character above U+FFFF, and NewStringUTF expects modified
 * UTF-8 on the way back. Worked Kotlin + C example, and why:
 * docs/ANDROID_JNI_BRIDGE.md.
 */

#ifndef BALLISTICS_BRIDGE_H
#define BALLISTICS_BRIDGE_H

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Process one bridge request (NUL-terminated UTF-8 JSON envelope). */
char *ballistics_bridge_call(const char *request_json);

/* Length-explicit variant for buffers that are not NUL-terminated. */
char *ballistics_bridge_call_n(const uint8_t *request, size_t len);

/* Release a response returned by either call. NULL is a no-op. */
void ballistics_bridge_free(char *response);

#ifdef __cplusplus
}
#endif

#endif /* BALLISTICS_BRIDGE_H */