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.
gridDistanceis 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
7is 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
- Core library overview — the layering and types
- Algorithms — what a reimplementation must reproduce
- Language bindings — the existing bindings
The Terra System is designed and developed by Tec Solution KSA.