Encode and decode lists of coordinates as compact ASCII strings. Implements Google's Encoded Polyline Algorithm Format · Spec v0.1.1 · Conformance: core ✓ full ✓ (44/44)
Coordinate order:
LonLatis(lon, lat); the encoded string stores latitude first. The library converts at the boundary.
Requires Zig 0.17.0. Standard library only.
zig fetch --save git+https://github.com/Xenoglyphiq/polyline-zig#v0.1.0
Then in build.zig:
const polyline = b.dependency("polyline", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("polyline", polyline.module("polyline"));const polyline = @import("polyline");
const text = try polyline.encode(gpa, &.{
.{ .lon = -120.2, .lat = 38.5 },
.{ .lon = -120.95, .lat = 40.7 },
}, .{}, null);
defer gpa.free(text);
const points = try polyline.decode(gpa, text, .{}, null);
defer gpa.free(points);Every allocating call takes the allocator first; the caller owns and frees the result.
Run all three with zig build examples.
const route = [_]polyline.LonLat{
.{ .lon = -120.2, .lat = 38.5 },
.{ .lon = -120.95, .lat = 40.7 },
.{ .lon = -126.453, .lat = 43.252 },
};
const text = try polyline.encode(init.gpa, &route, .{}, null);
defer init.gpa.free(text);
// _p~iF~ps|U_ulLnnqC_mqNvxq`@var diag: polyline.Diagnostics = .{};
const points = polyline.decode(init.gpa, "_p~iF~ps|U_ulLnnqC_mqNvxq`@", .{}, &diag) catch |err| {
std.debug.print("{s}: {s} at byte {?d}\n", .{ @errorName(err), diag.code, diag.offset });
return err;
};
defer init.gpa.free(points);
for (points) |p| std.debug.print("lon {d}, lat {d}\n", .{ p.lon, p.lat });const opts: polyline.Options = .{ .precision = 6 }; // OSRM, Valhalla
const text = try polyline.encode(init.gpa, &route, opts, null);
defer init.gpa.free(text);
const back = try polyline.decode(init.gpa, text, opts, null);
defer init.gpa.free(back);| Limit | Default | Option name |
|---|---|---|
| Points accepted or produced | 1,000,000 | Options.max_points |
Input length for decode |
16 MiB | Options.max_text_length |
Precision (1–10, default 5) is Options.precision.
Errors are the error set polyline.Error, whose names are the spec's kinds: InvalidInput and LimitExceeded (plus Zig's OutOfMemory). Pass a *polyline.Diagnostics to get the stable code (such as polyline.invalid_char) and, where defined, the byte offset. Full list: spec §3.
\ is a valid polyline character. Strings copied from JavaScript source often contain \\ escapes and decode to different points without any error.
| Module | Layer | Needs |
|---|---|---|
polyline |
core | nothing beyond the standard library |
There is no io layer: everything works on in-memory slices.
| Command | What |
|---|---|
zig build test |
Unit tests |
zig build test --fuzz=1M |
Fuzz the decoder |
zig build conformance |
Every case in .spec/conformance/manifest.json |
zig build examples |
The three canonical examples |
zig build bench |
Timings on .spec/bench/route_100k.polyline (always ReleaseFast; method in .spec/bench/README.md) |
| Benchmark | Reference | This port | Ratio |
|---|---|---|---|
| Encode 100k points | Rust polyline 0.11.0: 0.892 ms |
1.308 ms | 1.47× |
| Decode 100k points | Rust polyline 0.11.0: 0.643 ms |
0.642 ms | 1.00× |
Medians on .spec/bench/route_100k.polyline (100,000 points), measured 2026-10-05 on an Apple M5 Pro with zig build bench (ReleaseFast), Zig 0.17.0. Three rounds interleaved with the reference, following .spec/bench/README.md. Ratio = this port ÷ reference; the spec's target is within 2×.
MIT OR Apache-2.0