style: adopt TigerStyle across src/; add docs/TIGER_STYLE.md

Wrap signatures and long expressions to the 100-column limit and make every
file zig fmt clean. Semantics-preserving throughout: ignoring whitespace and
the trailing commas that wrapping introduces, every file here is byte-identical
to its predecessor, and the one apparent exception is a warning string split
with `++`, which concatenates at comptime to the same bytes.

src/index.zig and src/commands.zig are reformatted in the commits that follow,
because their reformat is interleaved with in-flight changes to them and
separating the two would need the reformat re-derived rather than moved.
This commit is contained in:
2026-08-03 17:08:21 +03:00
parent d4c9b04f21
commit 86ae8fa8af
14 changed files with 1130 additions and 126 deletions

View File

@@ -122,7 +122,11 @@ pub const Document = struct {
}
/// Serialize the full document (length-prefixed) into `out`.
pub fn to_bytes(self: *const Document, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) !void {
pub fn to_bytes(
self: *const Document,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) !void {
try write_doc(self.pairs, gpa, out);
}
};
@@ -157,7 +161,12 @@ const Parser = struct {
const ParseError = error{ InvalidBson, OutOfMemory };
fn parse_doc_into(allocator: std.mem.Allocator, bytes: []const u8, idx: *usize, borrow: bool) ParseError![]const Pair {
fn parse_doc_into(
allocator: std.mem.Allocator,
bytes: []const u8,
idx: *usize,
borrow: bool,
) ParseError![]const Pair {
const p = Parser{ .allocator = allocator, .bytes = bytes, .borrow = borrow };
return parse_doc_inner(p, idx);
}
@@ -356,7 +365,10 @@ fn parse_array(p: Parser, idx: *usize) ParseError![]const Value {
/// A borrowed parse of `bytes` into an arena: keys, strings, binary and
/// regex payloads point into `bytes`; only the pair/value skeleton is
/// allocated. The result is valid while both `bytes` and `arena` live.
pub fn spine(allocator: std.mem.Allocator, bytes: []const u8) error{ InvalidBson, OutOfMemory }![]const Pair {
pub fn spine(
allocator: std.mem.Allocator,
bytes: []const u8,
) error{ InvalidBson, OutOfMemory }![]const Pair {
var idx: usize = 0;
return parse_doc_into(allocator, bytes, &idx, true);
}
@@ -414,7 +426,12 @@ pub fn skip_value(bytes: []const u8, idx: *usize, tag: u8) error{InvalidBson}!vo
/// Read one value of `tag` into a Value whose leaves borrow `bytes`; nested
/// documents and arrays materialize their spines into `arena`. Advances
/// `idx` past the value.
pub fn read_value(allocator: std.mem.Allocator, bytes: []const u8, idx: *usize, tag: u8) error{ InvalidBson, OutOfMemory }!Value {
pub fn read_value(
allocator: std.mem.Allocator,
bytes: []const u8,
idx: *usize,
tag: u8,
) error{ InvalidBson, OutOfMemory }!Value {
switch (tag) {
0x01 => {
try ensure_available(bytes, idx.*, 8);
@@ -542,7 +559,11 @@ pub fn read_value(allocator: std.mem.Allocator, bytes: []const u8, idx: *usize,
/// The value stored under `key` in a document's bytes, or null when absent.
/// Nested documents and arrays materialize their spines into `arena`.
pub fn get_at(arena: std.mem.Allocator, bytes: []const u8, key: []const u8) error{ InvalidBson, OutOfMemory }!?Value {
pub fn get_at(
arena: std.mem.Allocator,
bytes: []const u8,
key: []const u8,
) error{ InvalidBson, OutOfMemory }!?Value {
var idx: usize = 4;
while (idx + 1 < bytes.len and bytes[idx] != 0) {
const tag = bytes[idx];
@@ -565,7 +586,11 @@ pub const SerializeError = error{
OutOfMemory,
};
pub fn write_value(v: Value, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) SerializeError!void {
pub fn write_value(
v: Value,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) SerializeError!void {
switch (v) {
.double => |d| {
var buf: [8]u8 = undefined;
@@ -618,13 +643,21 @@ pub fn write_value(v: Value, gpa: std.mem.Allocator, out: *std.ArrayListUnmanage
}
}
pub fn write_cstring(s: []const u8, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) SerializeError!void {
pub fn write_cstring(
s: []const u8,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) SerializeError!void {
if (std.mem.indexOfScalar(u8, s, 0) != null) return error.BsonNulInKey;
try out.appendSlice(gpa, s);
try out.append(gpa, 0);
}
pub fn write_string(s: []const u8, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) SerializeError!void {
pub fn write_string(
s: []const u8,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) SerializeError!void {
if (s.len + 1 > std.math.maxInt(u32)) return error.BsonTooLarge;
var buf: [4]u8 = undefined;
std.mem.writeInt(u32, &buf, @intCast(s.len + 1), .little);
@@ -633,7 +666,11 @@ pub fn write_string(s: []const u8, gpa: std.mem.Allocator, out: *std.ArrayListUn
try out.append(gpa, 0);
}
pub fn write_element(pair: Pair, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) SerializeError!void {
pub fn write_element(
pair: Pair,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) SerializeError!void {
try out.append(gpa, pair.value.type_tag());
try write_cstring(pair.key, gpa, out);
try write_value(pair.value, gpa, out);
@@ -648,7 +685,11 @@ fn begin_frame(gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) Seriali
}
/// Terminate the frame opened at `len_pos` and patch in its total length.
fn end_frame(gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8), len_pos: usize) SerializeError!void {
fn end_frame(
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
len_pos: usize,
) SerializeError!void {
try out.append(gpa, 0);
const total = out.items.len - len_pos;
if (total > std.math.maxInt(u32)) return error.BsonTooLarge;
@@ -656,13 +697,21 @@ fn end_frame(gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8), len_pos:
}
/// Write a length-prefixed document. Length is patched in after the body.
pub fn write_doc(pairs: []const Pair, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) SerializeError!void {
pub fn write_doc(
pairs: []const Pair,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) SerializeError!void {
const len_pos = try begin_frame(gpa, out);
for (pairs) |p| try write_element(p, gpa, out);
try end_frame(gpa, out, len_pos);
}
fn write_array(items: []const Value, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) SerializeError!void {
fn write_array(
items: []const Value,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) SerializeError!void {
const len_pos = try begin_frame(gpa, out);
var buf: [16]u8 = undefined;
for (items, 0..) |item, i| {
@@ -686,7 +735,11 @@ pub fn serialize_value(gpa: std.mem.Allocator, v: Value) ![]u8 {
/// Append the serialized-key bytes of `v` (type tag + payload) to `out`. The
/// appending form of serialize_value, for callers reusing one scratch buffer
/// across many keys.
pub fn write_serialized_value(v: Value, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) !void {
pub fn write_serialized_value(
v: Value,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) !void {
try out.append(gpa, v.type_tag());
try write_value(v, gpa, out);
}
@@ -709,7 +762,10 @@ pub fn copy_value(arena: std.mem.Allocator, v: Value) std.mem.Allocator.Error!Va
};
}
pub fn copy_pairs(arena: std.mem.Allocator, pairs: []const Pair) std.mem.Allocator.Error![]const Pair {
pub fn copy_pairs(
arena: std.mem.Allocator,
pairs: []const Pair,
) std.mem.Allocator.Error![]const Pair {
const out = try arena.alloc(Pair, pairs.len);
for (pairs, 0..) |p, i| {
out[i] = .{ .key = try arena.dupe(u8, p.key), .value = try copy_value(arena, p.value) };
@@ -717,7 +773,10 @@ pub fn copy_pairs(arena: std.mem.Allocator, pairs: []const Pair) std.mem.Allocat
return out;
}
fn copy_values(arena: std.mem.Allocator, items: []const Value) std.mem.Allocator.Error![]const Value {
fn copy_values(
arena: std.mem.Allocator,
items: []const Value,
) std.mem.Allocator.Error![]const Value {
const out = try arena.alloc(Value, items.len);
for (items, 0..) |item, i| out[i] = try copy_value(arena, item);
return out;
@@ -879,7 +938,11 @@ pub fn encoded_leading_datetime(key: []const u8) ?i64 {
/// ambiguous. Escaping `00` as `00 FF` fixes both problems at once: a real
/// NUL encodes above the `00 00` terminator, and any byte >= 01 is above it
/// too, so "shorter is less" falls out to match `std.mem.order`.
fn encode_escaped(bytes: []const u8, gpa: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8)) !void {
fn encode_escaped(
bytes: []const u8,
gpa: std.mem.Allocator,
out: *std.ArrayListUnmanaged(u8),
) !void {
for (bytes) |b| {
try out.append(gpa, b);
if (b == 0x00) try out.append(gpa, 0xFF);
@@ -1128,23 +1191,47 @@ test "encode_key order matches bson.compare on every pair" {
.min_key,
.null,
// Numbers: cross-type equality, sign, zero, extremes, NaN.
.{ .int32 = -2147483648 }, .{ .int32 = -1 }, .{ .int32 = 0 },
.{ .int32 = 1 }, .{ .int32 = 2 }, .{ .int32 = 2147483647 },
.{ .int64 = -9223372036854775807 }, .{ .int64 = -1 }, .{ .int64 = 0 },
.{ .int64 = 1 }, .{ .int64 = 9223372036854775807 },
.{ .double = -std.math.inf(f64) }, .{ .double = -1.5 }, .{ .double = -0.0 },
.{ .double = 0.0 }, .{ .double = 0.5 }, .{ .double = 1.0 },
.{ .double = 1.5 }, .{ .double = std.math.inf(f64) },
.{ .int32 = -2147483648 },
.{ .int32 = -1 },
.{ .int32 = 0 },
.{ .int32 = 1 },
.{ .int32 = 2 },
.{ .int32 = 2147483647 },
.{ .int64 = -9223372036854775807 },
.{ .int64 = -1 },
.{ .int64 = 0 },
.{ .int64 = 1 },
.{ .int64 = 9223372036854775807 },
.{ .double = -std.math.inf(f64) },
.{ .double = -1.5 },
.{ .double = -0.0 },
.{ .double = 0.0 },
.{ .double = 0.5 },
.{ .double = 1.0 },
.{ .double = 1.5 },
.{ .double = std.math.inf(f64) },
.{ .double = std.math.nan(f64) },
// Strings, including embedded NUL and prefix relationships.
.{ .string = "" }, .{ .string = "\x00" }, .{ .string = "\x00b" },
.{ .string = "a" }, .{ .string = "a\x00" }, .{ .string = "a\x00b" },
.{ .string = "ab" }, .{ .string = "b" }, .{ .string = "\xff" },
.{ .string = "" },
.{ .string = "\x00" },
.{ .string = "\x00b" },
.{ .string = "a" },
.{ .string = "a\x00" },
.{ .string = "a\x00b" },
.{ .string = "ab" },
.{ .string = "b" },
.{ .string = "\xff" },
// Same rank as string, so these must interleave with them.
.{ .symbol = "a" }, .{ .code = "ab" },
.{ .doc = &.{} }, .{ .doc = &nested }, .{ .doc = &nested2 },
.{ .doc = &nested_l }, .{ .doc = &two_pairs },
.{ .array = &.{} }, .{ .array = &arr1 }, .{ .array = &arr2 },
.{ .symbol = "a" },
.{ .code = "ab" },
.{ .doc = &.{} },
.{ .doc = &nested },
.{ .doc = &nested2 },
.{ .doc = &nested_l },
.{ .doc = &two_pairs },
.{ .array = &.{} },
.{ .array = &arr1 },
.{ .array = &arr2 },
.{ .array = &arr_str },
// Binary orders by length first, then bytes, then subtype.
.{ .binary = .{ .subtype = 0, .data = "" } },
@@ -1155,11 +1242,15 @@ test "encode_key order matches bson.compare on every pair" {
.{ .object_id = [_]u8{0} ** 12 },
.{ .object_id = [_]u8{0} ** 11 ++ [_]u8{1} },
.{ .object_id = [_]u8{255} ** 12 },
.{ .bool = false }, .{ .bool = true },
.{ .datetime = std.math.minInt(i64) }, .{ .datetime = -1 },
.{ .datetime = 0 }, .{ .datetime = 1 },
.{ .bool = false },
.{ .bool = true },
.{ .datetime = std.math.minInt(i64) },
.{ .datetime = -1 },
.{ .datetime = 0 },
.{ .datetime = 1 },
.{ .datetime = std.math.maxInt(i64) },
.{ .timestamp = 0 }, .{ .timestamp = 1 },
.{ .timestamp = 0 },
.{ .timestamp = 1 },
.{ .timestamp = std.math.maxInt(u64) },
.{ .regex = .{ .pattern = "a", .options = "" } },
.{ .regex = .{ .pattern = "a", .options = "i" } },
@@ -1199,9 +1290,9 @@ test "encode_key concatenates into unambiguous compound keys" {
// against the component-wise order they are supposed to reproduce.
const gpa = testing.allocator;
const parts = [_]Value{
.{ .string = "" }, .{ .string = "a" }, .{ .string = "a\x00" },
.{ .string = "ab" }, .{ .int32 = 1 }, .{ .int32 = 2 },
.null, .{ .array = &.{} }, .{ .bool = true },
.{ .string = "" }, .{ .string = "a" }, .{ .string = "a\x00" },
.{ .string = "ab" }, .{ .int32 = 1 }, .{ .int32 = 2 },
.null, .{ .array = &.{} }, .{ .bool = true },
};
for (parts) |a1| {