Skip to main content

Creating bindings

The core library is designed to be wrapped. This page covers what a binding must do to be correct, and the conformance properties it must satisfy.

Approaches​

Foreign function interface — call terra-core directly through the host language's FFI. Fastest to build and guarantees identical results, since it is the same code. Requires shipping a native binary per platform.

WebAssembly — compile terra-core to WASM. The route used by the JavaScript binding. One artefact runs everywhere, at some cost in call overhead.

Reimplementation — port the algorithms natively, as the Go binding does to avoid a CGo dependency. Removes the native-binary problem entirely, at the cost of having to keep two implementations in agreement. Only take this route if you will run the conformance suite in CI.

What a binding must get right​

Represent cells without precision loss. A cell is an unsigned 64-bit integer. Languages without a native unsigned 64-bit type must use the TIS string, a big-integer type, or two 32-bit halves.

In JavaScript every Terra index exceeds Number.MAX_SAFE_INTEGER, so a cell in a Number is silently corrupted — not an edge case, but every cell. This is the single most common binding defect.

Surface errors idiomatically. The core returns TerraError codes; the binding should translate them into whatever the host language expects — exceptions, returned errors, or null. Do not leak raw numeric codes as the primary interface, and do not discard them.

Follow host naming conventions. latLngToCell in JavaScript, lat_lng_to_cell in Python, LatLngToCell in Go, terra_lat_lng_to_cell in SQL. A binding that imports C naming wholesale reads as foreign in every language it is used from.

Size output buffers correctly. Where the core writes into caller-allocated arrays, the binding must call the corresponding sizing helper rather than guessing. Under- allocation is a buffer overflow, not an error return.

Provide batch entry points. Per-call overhead across a binding boundary dominates at scale. Anything expected to process thousands of cells should accept and return arrays rather than requiring a loop on the host side.

Conformance​

A binding is correct when it reproduces the core's results exactly. The properties below are necessary and are what the conformance suite checks.

Round trips

  • A coordinate indexed to a cell and back returns the cell centre, within the cell's own extent.
  • A cell converted to TIS and back is unchanged.
  • A cell converted to TGC and back is unchanged, and the check character validates.
  • A cell taken to a child and back to its parent is unchanged.

Grid invariants

  • Every cell has exactly six neighbours, at every resolution, with no exceptions.
  • Every parent has exactly seven children.
  • gridRing(cell, k) returns exactly 6k cells for k ≥ 1.
  • gridDisk(cell, k) returns exactly 3k² + 3k + 1 cells.
  • Cell area is constant for a given resolution anywhere in the extent.
  • gridDistance is symmetric, zero only for identical cells, and satisfies the triangle inequality.

Validity

  • A cell with a non-zero reserved field is invalid.
  • A cell with a digit beyond its resolution not equal to 7 is invalid.
  • A cell with a resolution above 14 is invalid.
  • A TGC failing its check character is rejected, not corrected.

Cross-implementation

The definitive test: index the same coordinates at the same resolutions through the new binding and through an established one, and compare. Any divergence is a defect in the new binding.

Publishing​

A binding intended for general use should state which terra-core version it wraps, report gridVersion() unchanged from the core, pass the conformance suite in CI on every supported platform, and document its cell representation prominently — that is the first thing an integrator needs to know.

Next​


The Terra System is designed and developed by Tec Solution KSA.