Skip to content

[Cosmos]: Implement azure_data_cosmos_driver Native Wrapper #4372

@kundadebdatta

Description

@kundadebdatta

azure_data_cosmos_driver_native — Native (C ABI) Wrapper Spec

Field Value
Status Draft / Task
Owner Cosmos DB Rust SDK team
Target crate sdk/cosmos/azure_data_cosmos_driver_native
Wraps azure_data_cosmos_driver
Reference work PR #4103 — removal of the prior azure_data_cosmos_native (which wrapped azure_data_cosmos)
Tracking issue TBD

1. Background

The Cosmos DB Rust workspace previously contained sdk/cosmos/azure_data_cosmos_native, a C-ABI
wrapper crate that exposed the high-level azure_data_cosmos SDK surface (typed
clients: CosmosClient, Database, Container) over a C API generated with cbindgen,
built as cdylib/staticlib, packaged with pkg-config (azurecosmos.pc.in), and
exercised by a CMake-driven C test harness (c_tests/*.c).

That crate was deleted in PR #4103 ("Cosmos: remove azure_data_cosmos_native",
issue #4090 — perpetual
rebuild churn). Per the PR description, the deletion is intentionally temporary: it
will be restored later when doing work on the native wrapper for the driver. This
spec defines that restoration.

The new wrapper differs from the deleted one in three fundamental ways:

  1. It wraps the driver, not the SDK. The driver (azure_data_cosmos_driver) is
    the schema-agnostic core implementation, deliberately designed for cross-language
    reuse (per AGENTS.md §"Multi-Crate Strategy"). Wrapping the
    driver — not azure_data_cosmos — removes the serde::Serialize / Deserialize
    item-type bound from the FFI surface and matches the documented architectural intent.
  2. Data plane is byte-oriented. Per the AGENTS.md "Schema-Agnostic Data Plane"
    section, request bodies are &[u8] and response bodies are Vec<u8>. The C API
    accepts and returns opaque buffers; serialization is the consuming language SDK's
    responsibility.
  3. Single-dispatch operation surface. The driver exposes
    CosmosDriver::execute_operation as the canonical
    data-plane entry point (one Rust function dispatching all operation kinds). The C
    API mirrors that shape, which collapses what was previously dozens of typed C
    functions into a small, stable surface.

2. Motivation

  • Cross-language SDK reuse is the raison d'être of the driver crate (see
    README.md and lib.rs crate doc-comment). Without
    a C ABI surface, that goal is aspirational rather than realized.
  • Validation of the driver's public API. Building a real, non-Rust consumer
    surfaces ergonomic issues (lifetimes leaking through, missing constructors,
    re-export gaps) that pure-Rust use does not.
  • Foundation for Java / .NET / Python SDKs. The native wrapper is the only
    supported integration path for SDKs in other languages; today there is none.
  • Recovers the test harness lost in Cosmos: remove azure_data_cosmos_native #4103. The C test programs
    (version.c, error_handling.c, item_crud.c, context_memory_management.c)
    exercised end-to-end FFI scenarios (lifetime, error propagation, payload round-trip)
    that have no equivalent in the current Rust-only tests.

3. Goals

  • G1. Ship a cdylib and staticlib exposing a stable C ABI for the driver's
    data-plane and control-plane surface, with a cbindgen-generated header.
  • G2. Provide a C/CMake build harness (CMakeLists.txt, pkg-config,
    DiscoverTests.cmake) so the wrapper is consumable from non-Rust toolchains.
  • G3. Provide an opaque-handle, _free-everything C API consistent with idiomatic FFI
    conventions (no Rust types leaked, no panics across the boundary).
  • G4. Provide a tokio-based runtime hosting layer so callers can submit async work
    without depending on a Rust runtime in their own process.
  • G5. Reach functional parity (data-plane CRUD, query/feed iteration, transactional
    batch, diagnostics readback, fault injection toggles) with the driver's Rust API.
  • G6. Deliver a CMake-driven C test harness mirroring the four programs from Cosmos: remove azure_data_cosmos_native #4103
    (version, error handling, item CRUD, context/memory management), plus new tests
    for query/feed iteration and diagnostics.
  • G7. Wire the new crate back into the workspace, dictionaries, dependency-verification
    exemption list, and design-struct/pre-commit skill scopes — i.e., undo the
    surgical removals made by Cosmos: remove azure_data_cosmos_native #4103.
  • G8. Avoid re-introducing the rebuild churn that motivated azure_data_cosmos_native always gets rebuilt whenever I run cargo test #4090 (build-script
    hygiene; see §13).

4. Non-goals

  • NG1. Wrapping azure_data_cosmos. The high-level typed Rust SDK is not the
    wrap target. Item-type generic surfaces stay Rust-only.
  • NG2. Streaming I/O across the FFI. Cosmos enforces a 4 MB / 16 MB request /
    response payload cap; buffered byte slices are sufficient (mirrors AGENTS.md §
    "Streaming").
  • NG3. A Java / .NET / Python language binding. That work consumes this wrapper;
    it is not part of this spec.
  • NG4. A non-tokio runtime. A runtime/ module exists for future pluggability,
    but only the tokio backend ships in v1.
  • NG5. Source-compatibility with the deleted azure_data_cosmos_native C header.
    The new header has a different shape (driver-oriented, byte-buffer data plane);
    it is not a drop-in replacement for the deleted azurecosmos.h.

5. Stakeholders

  • Cosmos Rust SDK team — owns the crate, header, and CI.
  • Cross-language SDK teams (Java/.NET/Python) — primary consumers, will exercise
    this surface against real workloads.
  • Driver crate maintainers — must accept additional public-API stability
    obligations once the wrapper ships (re-exports / signature changes become
    ABI-affecting).

6. Reference: prior implementation (PR #4103, deleted)

The deleted azure_data_cosmos_native had this layout (kept here so the new crate can
copy what was sound and discard what was schema-coupled):

sdk/cosmos/azure_data_cosmos_native/   (DELETED in PR #4103)
├── .gitignore
├── Cargo.toml                          # cdylib + staticlib, cbindgen build-dep
├── CMakeLists.txt                      # builds + runs C tests
├── README.md                           # 341 lines
├── azurecosmos.pc.in                   # pkg-config template
├── build.rs                            # cbindgen header generation (126 lines)
├── cmake/DiscoverTests.cmake           # ctest discovery glue
├── docs/next_generation_sdks_design_principles.md  # 240 lines
├── include/azurecosmos.h               # generated, 639 lines
├── src/
│   ├── lib.rs                          # 80 lines, panic hook + crate doc
│   ├── error.rs                        # 315 lines, error code enum + last-error TLS
│   ├── context.rs                      # 272 lines, opaque "context" handle (auth, options)
│   ├── string.rs                       # 57 lines, CStr/CString helpers
│   ├── options/mod.rs                  # 66 lines, options translation
│   ├── runtime/{mod.rs,tokio.rs}       # 77+46 lines, tokio runtime hosting
│   └── clients/
│       ├── mod.rs
│       ├── cosmos_client.rs            # 212 lines  (TYPED — TO BE REPLACED)
│       ├── database_client.rs          # 184 lines  (TYPED — TO BE REPLACED)
│       └── container_client.rs         # 307 lines  (TYPED — TO BE REPLACED)
└── c_tests/
    ├── test_common.h                   # 311 lines
    ├── version.c                       # 22 lines
    ├── error_handling.c                # 267 lines
    ├── item_crud.c                     # 59 lines
    └── context_memory_management.c     # 151 lines

Reusable patterns (carry forward verbatim or with light edits):

  • Cargo [lib] crate-type = ["cdylib", "staticlib"]
  • cbindgen build-script header generation
  • panic = "abort" policy at the FFI boundary, plus std::panic::catch_unwind wrapping every extern "C" entry point
  • Last-error thread-local + *_get_last_error_message accessor pattern (error.rs)
  • CStr / CString helpers (string.rs)
  • Tokio Runtime::new_multi_thread() hosting (runtime/tokio.rs)
  • CMake harness + pkg-config + DiscoverTests.cmake

Patterns to discard / redesign:

  • Typed cosmos_client.rs / database_client.rs / container_client.rs surfaces
    (replace with a single dispatch over CosmosDriver::execute_operation).
  • Any item-shape coupling (none should leak; data plane is const uint8_t* + size_t).
  • The "native" part of the crate name (use azure_data_cosmos_driver_native to make
    the wrap target unambiguous and to avoid collision with the historical name).

7. Proposed crate

7.1 Layout

sdk/cosmos/azure_data_cosmos_driver_native/
├── .gitignore
├── Cargo.toml
├── CHANGELOG.md
├── CMakeLists.txt
├── README.md
├── azurecosmosdriver.pc.in
├── build.rs                            # cbindgen
├── cmake/
│   └── DiscoverTests.cmake
├── docs/
│   └── DESIGN.md                       # ABI conventions, lifetime/threading model
├── include/                            # cbindgen output checked-in for diffability
│   └── azure_data_cosmos_driver.h
├── src/
│   ├── lib.rs                          # crate doc, panic hook, version export
│   ├── abi.rs                          # status codes, panic guard, ffi macros
│   ├── error.rs                        # last-error TLS + diagnostic accessors
│   ├── string.rs                       # CStr/CString helpers
│   ├── runtime/
│   │   ├── mod.rs                      # CosmosRuntimeHandle opaque type
│   │   └── tokio.rs                    # default tokio multi-thread runtime
│   ├── handle.rs                       # generic Box<T> -> *mut T helpers
│   ├── driver.rs                       # CosmosDriverHandle (wraps CosmosDriver)
│   ├── credential.rs                   # TokenCredential FFI (key + token-callback)
│   ├── options.rs                      # DriverOptions / per-op options translation
│   ├── operation.rs                    # request builder + execute_operation dispatch
│   ├── response.rs                     # CosmosResponseHandle (body bytes + metadata)
│   ├── diagnostics.rs                  # DiagnosticsContext readback
│   ├── feed.rs                         # paginated feed iterator (query/change feed/read-many)
│   ├── batch.rs                        # transactional batch builder
│   └── fault_injection.rs              # behind cargo feature, mirrors driver feature
└── c_tests/
    ├── test_common.h
    ├── version.c
    ├── error_handling.c
    ├── context_memory_management.c
    ├── item_crud.c
    ├── query_feed.c                    # NEW
    ├── batch.c                         # NEW
    └── diagnostics.c                   # NEW

7.2 Cargo.toml shape

[package]
name = "azure_data_cosmos_driver_native"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "C ABI wrapper around azure_data_cosmos_driver for cross-language SDK reuse."
repository = "https://github.com/Azure/azure-sdk-for-rust"

[lib]
crate-type = ["cdylib", "staticlib"]

[features]
default = []
fault_injection = ["azure_data_cosmos_driver/fault_injection"]

[dependencies]
azure_data_cosmos_driver = { path = "../azure_data_cosmos_driver" }
azure_core = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread"] }
tracing = { workspace = true }

[build-dependencies]
cbindgen = "0.27"

7.3 ABI conventions (codified in src/abi.rs)

  • All entry points are #[no_mangle] pub unsafe extern "C" and named with the
    prefix azure_cosmos_driver_<noun>_<verb> (e.g. azure_cosmos_driver_create,
    azure_cosmos_driver_response_free).
  • Every entry point returns an int32_t status code (AZ_COSMOS_DRIVER_OK = 0,
    negative for errors). Out-parameters via *mut *mut T for handles, *mut size_t
    for byte counts.
  • Every entry point is wrapped in std::panic::catch_unwind; any panic returns
    AZ_COSMOS_DRIVER_E_PANIC and stores the panic message in the last-error TLS.
  • All handles are opaque (typedef struct AzureCosmosDriver AzureCosmosDriver;),
    constructed by _create, destroyed by _free. Double-free is UB but _free(NULL)
    is a no-op.
  • Strings into the wrapper are NUL-terminated UTF-8 const char*. Strings out are
    borrowed from a handle (caller copies) or owned strings returned with a paired
    _string_free function — never both, and the contract is documented per call.
  • Byte buffers are (const uint8_t* data, size_t len) going in and
    (const uint8_t* data, size_t len) borrowed from a CosmosResponse handle going
    out (freed with the response handle).
  • Threading: handles are Send + Sync unless explicitly documented otherwise. The
    runtime, driver, and response handles are safe to share across threads.

7.4 Surface (header sketch)

/* Status codes */
typedef int32_t az_cosmos_driver_status_t;
#define AZ_COSMOS_DRIVER_OK        0
#define AZ_COSMOS_DRIVER_E_INVALID -1
#define AZ_COSMOS_DRIVER_E_PANIC   -2
#define AZ_COSMOS_DRIVER_E_HTTP    -3
/* ... mapped from driver error categories ... */

/* Last-error accessors (TLS) */
const char* azure_cosmos_driver_last_error_message(void);
int32_t     azure_cosmos_driver_last_error_status_code(void);

/* Runtime */
typedef struct AzureCosmosDriverRuntime AzureCosmosDriverRuntime;
az_cosmos_driver_status_t azure_cosmos_driver_runtime_create(
    AzureCosmosDriverRuntime** out);
void                       azure_cosmos_driver_runtime_free(
    AzureCosmosDriverRuntime* rt);

/* Credential */
typedef struct AzureCosmosDriverCredential AzureCosmosDriverCredential;
az_cosmos_driver_status_t azure_cosmos_driver_credential_from_key(
    const char* key, AzureCosmosDriverCredential** out);
typedef int32_t (*az_cosmos_driver_token_callback)(
    void* user_data,
    const char* const* scopes, size_t scopes_len,
    char** out_token, int64_t* out_expires_unix_ms);
az_cosmos_driver_status_t azure_cosmos_driver_credential_from_callback(
    az_cosmos_driver_token_callback cb, void* user_data,
    AzureCosmosDriverCredential** out);
void azure_cosmos_driver_credential_free(AzureCosmosDriverCredential* c);

/* Driver */
typedef struct AzureCosmosDriver AzureCosmosDriver;
az_cosmos_driver_status_t azure_cosmos_driver_create(
    AzureCosmosDriverRuntime* rt,
    const char* endpoint,
    AzureCosmosDriverCredential* credential,
    const uint8_t* options_json, size_t options_json_len, /* optional, may be NULL/0 */
    AzureCosmosDriver** out);
void azure_cosmos_driver_free(AzureCosmosDriver* d);

/* Operation request + execute */
typedef struct AzureCosmosDriverRequest  AzureCosmosDriverRequest;
typedef struct AzureCosmosDriverResponse AzureCosmosDriverResponse;

az_cosmos_driver_status_t azure_cosmos_driver_request_new(
    int32_t op_kind,                           /* enum mirroring OperationKind */
    const char* database, const char* container,
    AzureCosmosDriverRequest** out);
az_cosmos_driver_status_t azure_cosmos_driver_request_set_partition_key(
    AzureCosmosDriverRequest* req,
    const uint8_t* pk_bytes, size_t pk_len);  /* serialized PK */
az_cosmos_driver_status_t azure_cosmos_driver_request_set_body(
    AzureCosmosDriverRequest* req,
    const uint8_t* body, size_t body_len);
az_cosmos_driver_status_t azure_cosmos_driver_request_set_header(
    AzureCosmosDriverRequest* req, const char* name, const char* value);
void azure_cosmos_driver_request_free(AzureCosmosDriverRequest* req);

az_cosmos_driver_status_t azure_cosmos_driver_execute(
    AzureCosmosDriver* driver,
    AzureCosmosDriverRequest* req,
    AzureCosmosDriverResponse** out);

/* Response */
az_cosmos_driver_status_t azure_cosmos_driver_response_body(
    const AzureCosmosDriverResponse* resp,
    const uint8_t** out_data, size_t* out_len);
int32_t  azure_cosmos_driver_response_status(const AzureCosmosDriverResponse* resp);
double   azure_cosmos_driver_response_request_charge(const AzureCosmosDriverResponse* resp);
const char* azure_cosmos_driver_response_activity_id(const AzureCosmosDriverResponse* resp);
const char* azure_cosmos_driver_response_session_token(const AzureCosmosDriverResponse* resp);
const char* azure_cosmos_driver_response_continuation(const AzureCosmosDriverResponse* resp);
void azure_cosmos_driver_response_free(AzureCosmosDriverResponse* resp);

/* Diagnostics */
az_cosmos_driver_status_t azure_cosmos_driver_response_diagnostics_json(
    const AzureCosmosDriverResponse* resp,
    char** out_json);  /* paired with azure_cosmos_driver_string_free */
void azure_cosmos_driver_string_free(char* s);

/* Pagination — query / change feed / read-many */
typedef struct AzureCosmosDriverFeed AzureCosmosDriverFeed;
az_cosmos_driver_status_t azure_cosmos_driver_feed_open(
    AzureCosmosDriver* driver,
    AzureCosmosDriverRequest* initial_req,
    AzureCosmosDriverFeed** out);
az_cosmos_driver_status_t azure_cosmos_driver_feed_next(
    AzureCosmosDriverFeed* feed,
    AzureCosmosDriverResponse** out_page,
    int32_t* out_done);
void azure_cosmos_driver_feed_free(AzureCosmosDriverFeed* feed);

/* Transactional batch */
typedef struct AzureCosmosDriverBatch AzureCosmosDriverBatch;
/* ... batch_new / batch_add_create / batch_add_replace / ... / batch_execute / batch_free ... */

/* Versioning */
const char* azure_cosmos_driver_version(void);  /* CARGO_PKG_VERSION */
uint32_t    azure_cosmos_driver_abi_version(void);

7.5 Mapping to driver Rust API

C function Rust call
azure_cosmos_driver_runtime_create construct tokio::runtime::Runtime in runtime::tokio; wrap in CosmosDriverRuntime
azure_cosmos_driver_create CosmosDriverBuilder::new(endpoint, credential, options).build() (then .initialize())
azure_cosmos_driver_execute CosmosDriver::execute_operation(req) (cosmos_driver.rs:1143)
azure_cosmos_driver_response_body borrows CosmosResponse::body
azure_cosmos_driver_response_diagnostics_json serde_json::to_string(&resp.diagnostics) (driver DiagnosticsContext)
azure_cosmos_driver_feed_* wraps a Stream<Item = CosmosResponse> (poll on the runtime)

8. Public API stability obligations on the driver

Wrapping the driver creates a chain: any breaking change to driver public types that
appear in this wrapper's translation layer becomes ABI-affecting. To keep the
wrapper resilient:

  • Translate driver enums (status codes, operation kinds, consistency levels) into
    wrapper-owned repr(C) enums in src/abi.rs. Never re-#[repr(C)] a driver
    type directly.
  • Keep options ingestion JSON-shaped (options_json: &[u8]) rather than struct-
    shaped at the FFI; the wrapper deserializes into DriverOptions internally. This
    insulates the C header from driver field additions.
  • Pin the driver dependency as path = "..." in v1; in v2 consider version = "x.y"
    with a strict compatibility band.

9. Build & packaging

  • cdylib and staticlib outputs.
  • build.rs runs cbindgen and writes to include/azure_data_cosmos_driver.h.
    Header is checked in (so reviewers and downstream consumers see ABI diffs in
    PRs).
  • azurecosmosdriver.pc.in produces a pkg-config file at install time
    (-lazure_data_cosmos_driver_native -ldl -lpthread -lm).
  • CMakeLists.txt provides:
    • cargo build --release invocation,
    • add_library(... IMPORTED) for the resulting artifact,
    • add_executable per C test, linked against the imported library,
    • include(cmake/DiscoverTests.cmake) to register tests with ctest.

10. Runtime model

  • A single AzureCosmosDriverRuntime opaque handle owns a tokio multi-thread runtime
    (default: worker_threads = num_cpus, configurable later via JSON options).
  • All async driver calls are dispatched onto that runtime via Handle::block_on from
    a non-runtime thread (the FFI caller's thread). No callback-based async in v1; the
    C entry points are blocking from the caller's perspective. (Async-callback variants
    may follow in v2; tracked separately.)
  • One runtime can be shared by multiple drivers; lifetime is enforced by ref-count
    inside the wrapper (Arc<TokioRuntime>).

11. Error handling

  • Wrapper-owned repr(C) error code enum, populated by translating
    azure_core::Error categories.
  • Last-error TLS holding (status, message); each entry point clears it on entry and
    populates it on failure.
  • Panics across the FFI boundary are caught and converted to AZ_COSMOS_DRIVER_E_PANIC;
    panic = "abort" is not set so catch_unwind can do its job.
  • Cosmos sub-status code, activity id, and RU charge are surfaced on the
    AzureCosmosDriverResponse for both success and error responses (mirrors AGENTS.md
    "Cosmos-specific errors should provide" list).

12. Testing

12.1 Rust unit tests (in-crate)

  • tests/abi_smoke.rs — handle round-trip, panic-guard behaviour, last-error TLS.
  • tests/options_translation.rs — JSON options → DriverOptions parity.

12.2 C integration tests (CMake / ctest)

Test Coverage
version.c azure_cosmos_driver_version matches CARGO_PKG_VERSION.
error_handling.c Bad endpoint, invalid options, NULL handle, panic catch, last-error TLS.
context_memory_management.c Lifetime: create/free pairs, double-free-of-NULL, cross-thread free.
item_crud.c Point CRUD round-trip via execute_operation, body byte-equality.
query_feed.c NEW. Multi-page query + change feed iteration, continuation handling.
batch.c NEW. Transactional batch (mixed ops, partial-failure read-back).
diagnostics.c NEW. DiagnosticsContext JSON shape, RU & activity-id presence.

12.3 Live tests

  • Gated behind RUSTFLAGS='--cfg test_category="emulator"' (mirrors driver
    convention).
  • CI lane: Linux + macOS + Windows × cosmos emulator container (where available).

13. Avoiding the rebuild churn that motivated #4090

Issue #4090 reported that
azure_data_cosmos_native rebuilt on every cargo test invocation. Mitigations:

  • build.rs uses cargo:rerun-if-changed= for the exact set of header-affecting
    source files only (not a directory wildcard).
  • cbindgen output is written to a target-relative path (OUT_DIR) for compilation,
    but copied to the checked-in include/ only when content changes (write-if-diff).
  • The crate is not added to the default workspace test plan; CI invokes it
    explicitly. Default cargo test from the workspace root excludes it via
    default-members configuration in the workspace Cargo.toml.
  • CMake step is opt-in (separate CI job), not invoked by cargo test.

14. Workspace re-integration (undoing PR #4103 surgically)

Files to re-edit (each previously had the native crate removed):

File Action
Cargo.toml (workspace) Add "sdk/cosmos/azure_data_cosmos_driver_native" to members.
eng/dict/crates.txt Add azure_data_cosmos_driver_native.
eng/dict/rust-custom.txt Add cbindgen.
eng/scripts/verify-dependencies.rs Add ("azure_data_cosmos_driver_native", "cbindgen") exemption.
sdk/cosmos/.cspell.json Re-add cmake, cstring, ctest, libazurecosmosdriver, makefiles, msvc, winget, **/*.h overrides.
sdk/cosmos/AGENTS.md Restore the azure_data_cosmos_driver_native consumer bullet under "Multi-Crate Strategy"; add a tokio-runtime note for the new crate.
sdk/cosmos/azure_data_cosmos_driver/README.md Restore "via the C API wrapper (azure_data_cosmos_driver_native)" phrasing.
sdk/cosmos/azure_data_cosmos_driver/src/lib.rs Restore C-API-wrapper sentence in crate doc-comment.
sdk/cosmos/.github/skills/cosmos-design-struct/SKILL.md Add azure_data_cosmos_driver_native to scope.
sdk/cosmos/.github/skills/cosmos-pre-commit-validation/SKILL.md Add azure_data_cosmos_driver_native to scope.

15. Phased delivery

Phase Scope Exit criterion
P1 — Skeleton Crate + Cargo.toml + lib.rs + abi.rs + version export + CMake hello + cbindgen. version.c test passes on Linux/macOS/Windows.
P2 — Lifecycle Runtime, credential, driver create/free, last-error TLS, panic guard. context_memory_management.c and error_handling.c pass.
P3 — Data plane Request builder + execute_operation + response readback. item_crud.c (point CRUD round-trip) passes against emulator.
P4 — Pagination & batch Feed handle (query/change feed/read-many) + transactional batch. query_feed.c and batch.c pass; continuation tokens round-trip.
P5 — Diagnostics & polish DiagnosticsContext JSON readback; fault injection feature flag. diagnostics.c passes; fault injection configurable from C.
P6 — CI & release Cross-OS CI matrix; pkg-config; checked-in header; CHANGELOG; README. Crate publishes from CI; downstream language SDK can consume from artifact.

16. Acceptance criteria

A1. sdk/cosmos/azure_data_cosmos_driver_native/ exists with the layout in §7.1 and
builds cleanly on Linux, macOS, and Windows.
A2. cargo build -p azure_data_cosmos_driver_native --release produces both cdylib
and staticlib artifacts.
A3. cargo fmt -p azure_data_cosmos_driver_native -- --check and
cargo clippy -p azure_data_cosmos_driver_native --all-features --all-targets
are clean.
A4. cbindgen regeneration is idempotent; running cargo build does not modify
include/azure_data_cosmos_driver.h unless source changed (guards #4090).
A5. All seven C tests in §12.2 pass under ctest against the Cosmos emulator
(where available) on the CI matrix.
A6. The wrapper does not depend on azure_data_cosmos; only on
azure_data_cosmos_driver, azure_core, tokio, tracing, and cbindgen
(build-only). Verified by cargo tree snapshot in CI.
A7. The wrapper exposes no Rust types in its public C header and no unsafe extern
function panics across the boundary (validated by error_handling.c's panic
sub-test).
A8. Every *_create / *_new entry point has a corresponding *_free; double-free
is documented as UB but _free(NULL) is verified to be a no-op.
A9. The §14 workspace re-integration changes are merged in the same PR as the new
crate.
A10. README and CHANGELOG cover: build instructions, runtime/lifetime model, error
handling contract, supported phases (per §15), and an honest support-model
statement (community/GitHub support — same as the driver crate).
A11. CHANGELOG follows cosmos.changelog.instructions.md.
A12. Default workspace cargo test does not build or run this crate (per §13);
dedicated CI lane does.

17. Open questions

  • Q1. Header naming: azure_data_cosmos_driver.h (verbose, matches crate) or
    azurecosmosdriver.h (compact, matches the deleted convention)? Recommend the
    former for clarity; revisit if downstream consumers object.
  • Q2. Should execute_operation accept the driver's OperationKind enum as an
    int32_t (compact, but version-coupled) or as a string discriminator
    ("create_item", etc.) (string-stable across driver bumps)? Recommend integer
    with a wrapper-owned repr(C) enum + an integer-stability test.
  • Q3. How should token-credential refresh be expressed across the FFI? The
    callback in §7.4 is one option; an alternative is a "push" model where the host
    language pre-fetches and sets a token. Recommend the callback pattern for v1.
  • Q4. Should v1 ship async callback entry points in addition to the blocking
    ones? Recommend deferring to v2 to keep the v1 surface small.
  • Q5. What is the public-API stability commitment for the C header in v1?
    Pre-1.0 (free to break) or stable from day one? Recommend pre-1.0; bump to 1.0
    only after at least one downstream consumer has shipped.

18. Risks

  • R1. ABI churn from driver evolution. Mitigated by the wrapper-owned enum
    pattern (§8) and JSON options ingestion.
  • R2. Rebuild churn returns. Mitigated by §13 build-script hygiene; gated by
    acceptance criterion A4.
  • R3. Tokio runtime conflicts with host language runtime. Documented in
    README; the runtime handle is explicit so callers can manage one process-wide.
  • R4. Panics leaking across the FFI. Mitigated by catch_unwind wrapper macro
    in abi.rs; gated by acceptance criterion A7.
  • R5. Header drift between checked-in copy and source. Mitigated by CI step
    that runs cargo build and fails if git diff include/ is non-empty.

19. References

Metadata

Metadata

Labels

CosmosThe azure_cosmos crateCosmos Native WrapperRelates to the Cosmos Native Wrapper (`azure_data_cosmos_native`)cosmos-driver

Type

Projects

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions