@pkmn/engine 0.1.0-dev.44a51703 → 0.1.0-dev.46307385

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ /// Stores state required by optional features to the engine that can be passed to a generation's
2
+ /// `Battle.update` function. All generations generically support protocol logging (enabled via
3
+ /// `-Dlog`), chance actions and probability tracking (enabled via `-Dchance`), and damage
4
+ /// computation and chance overrides (`-Dcalc`), though the concrete types for these features are
5
+ /// generation dependent.
6
+ pub fn Options(comptime Log: type, comptime Chance: type, comptime Calc: type) type {
7
+ return struct { log: Log, chance: Chance, calc: Calc };
8
+ }
9
+
10
+ /// Helper to create a battle `Options` object with the provided `log`, `chance`, and `calc`.
11
+ pub fn options(
12
+ log: anytype,
13
+ chance: anytype,
14
+ calc: anytype,
15
+ ) Options(@TypeOf(log), @TypeOf(chance), @TypeOf(calc)) {
16
+ return .{ .log = log, .chance = chance, .calc = calc };
17
+ }
@@ -10,18 +10,27 @@ pub fn print(value: anytype) void {
10
10
 
11
11
  nosuspend {
12
12
  stderr.writeAll("\x1b[41m") catch return;
13
- switch (@typeInfo(@TypeOf(value))) {
14
- .Struct => |info| {
15
- if (info.is_tuple) {
16
- inline for (info.fields, 0..) |f, i| {
17
- inspect(@field(value, f.name));
18
- if (i < info.fields.len - 1) stderr.writeAll(" ") catch return;
13
+ if (@TypeOf(@src()) == @TypeOf(value)) {
14
+ stderr.print("{s} ({s}:{d}:{d})", .{
15
+ value.fn_name,
16
+ value.file,
17
+ value.line,
18
+ value.column,
19
+ }) catch return;
20
+ } else {
21
+ switch (@typeInfo(@TypeOf(value))) {
22
+ .Struct => |info| {
23
+ if (info.is_tuple) {
24
+ inline for (info.fields, 0..) |f, i| {
25
+ inspect(@field(value, f.name));
26
+ if (i < info.fields.len - 1) stderr.writeAll(" ") catch return;
27
+ }
28
+ } else {
29
+ inspect(value);
19
30
  }
20
- } else {
21
- inspect(value);
22
- }
23
- },
24
- else => inspect(value),
31
+ },
32
+ else => inspect(value),
33
+ }
25
34
  }
26
35
  stderr.writeAll("\x1b[K\x1b[0m\n") catch return;
27
36
  }
@@ -0,0 +1,118 @@
1
+ const std = @import("std");
2
+
3
+ const assert = std.debug.assert;
4
+
5
+ const c = @cImport({
6
+ @cDefine("NAPI_VERSION", "8");
7
+ @cInclude("node_api.h");
8
+ });
9
+
10
+ pub const Array = struct {
11
+ pub fn init(env: c.napi_env, o: struct { length: ?usize }) c.napi_value {
12
+ var result: c.napi_value = undefined;
13
+ assert(c.napi_ok == if (o.length) |n|
14
+ c.napi_create_array_with_length(env, n, &result)
15
+ else
16
+ c.napi_create_array(env, &result));
17
+ return result;
18
+ }
19
+
20
+ pub fn set(env: c.napi_env, array: c.napi_value, index: u32, value: c.napi_value) void {
21
+ assert(c.napi_set_element(env, array, index, value) == c.napi_ok);
22
+ }
23
+ };
24
+
25
+ pub const Boolean = struct {
26
+ pub fn init(env: c.napi_env, value: bool) c.napi_value {
27
+ var result: c.napi_value = undefined;
28
+ assert(c.napi_get_boolean(env, value, &result) == c.napi_ok);
29
+ return result;
30
+ }
31
+ };
32
+
33
+ pub const Number = struct {
34
+ pub fn init(env: c.napi_env, value: anytype) c.napi_value {
35
+ const T = @TypeOf(value);
36
+ var result: c.napi_value = undefined;
37
+ assert(c.napi_ok == switch (@typeInfo(T)) {
38
+ .Int => |info| switch (info.bits) {
39
+ 0...32 => switch (info.signedness) {
40
+ .signed => c.napi_create_int32(env, @as(i32, value), &result),
41
+ .unsigned => c.napi_create_uint32(env, @as(u32, value), &result),
42
+ },
43
+ 33...52 => c.napi_create_int64(env, @as(i64, value), &result),
44
+ else => @compileError("int can't be represented as JS number"),
45
+ },
46
+ else => @compileError("expected number, got: " ++ @typeName(T)),
47
+ });
48
+ return result;
49
+ }
50
+
51
+ pub fn get(env: c.napi_env, value: c.napi_value, comptime T: type) T {
52
+ switch (@typeInfo(T)) {
53
+ .Int => |info| switch (info.bits) {
54
+ 0...32 => switch (info.signedness) {
55
+ .signed => {
56
+ var result: i32 = undefined;
57
+ assert(c.napi_get_value_int32(env, value, &result) == c.napi_ok);
58
+ return if (info.bits == 32) result else @intCast(result);
59
+ },
60
+ .unsigned => {
61
+ var result: u32 = undefined;
62
+ assert(c.napi_get_value_uint32(env, value, &result) == c.napi_ok);
63
+ return if (info.bits == 32) result else @intCast(result);
64
+ },
65
+ },
66
+ 33...63 => {
67
+ var result: i64 = undefined;
68
+ assert(c.napi_get_value_int64(env, value, &result) == c.napi_ok);
69
+ return @intCast(result);
70
+ },
71
+ else => {
72
+ var result: i64 = undefined;
73
+ assert(c.napi_get_value_int64(env, value, &result) == c.napi_ok);
74
+ return switch (info.signedness) {
75
+ .signed => value,
76
+ .unsigned => if (0 <= value) @intCast(value) else unreachable,
77
+ };
78
+ },
79
+ },
80
+ else => @compileError("expected number, got: " ++ @typeName(T)),
81
+ }
82
+ }
83
+ };
84
+
85
+ pub const Object = struct {
86
+ pub fn init(env: c.napi_env) c.napi_value {
87
+ var result: c.napi_value = undefined;
88
+ assert(c.napi_create_object(env, &result) == c.napi_ok);
89
+ return result;
90
+ }
91
+ };
92
+
93
+ pub const Property = union(enum) {
94
+ method: c.napi_callback,
95
+ value: c.napi_value,
96
+
97
+ pub fn init(comptime name: [:0]const u8, property: Property) c.napi_property_descriptor {
98
+ return .{
99
+ .utf8name = name,
100
+ .name = null,
101
+ .method = switch (property) {
102
+ .method => |m| m,
103
+ .value => null,
104
+ },
105
+ .getter = null,
106
+ .setter = null,
107
+ .value = switch (property) {
108
+ .method => null,
109
+ .value => |v| v,
110
+ },
111
+ .attributes = switch (property) {
112
+ .method => c.napi_default,
113
+ .value => c.napi_enumerable,
114
+ },
115
+ .data = null,
116
+ };
117
+ }
118
+ };
@@ -0,0 +1,60 @@
1
+ const std = @import("std");
2
+
3
+ const expect = std.testing.expect;
4
+ const assert = std.debug.assert;
5
+
6
+ // TODO: ziglang/zig#104
7
+ pub fn Optional(comptime T: type) type {
8
+ const fields = std.meta.fields(switch (@typeInfo(T)) {
9
+ .Bool => enum { false, true },
10
+ else => T,
11
+ });
12
+
13
+ var enumFields: [fields.len + 1]std.builtin.Type.EnumField = undefined;
14
+ var decls = [_]std.builtin.Type.Declaration{};
15
+
16
+ enumFields[0] = .{ .name = "None", .value = 0 };
17
+ inline for (fields, 1..) |field, i| {
18
+ assert(!std.mem.eql(u8, field.name, "None"));
19
+ enumFields[i] = .{
20
+ .name = field.name,
21
+ .value = i,
22
+ };
23
+ }
24
+
25
+ return @Type(.{
26
+ .Enum = .{
27
+ .tag_type = std.math.IntFittingRange(0, fields.len + 1),
28
+ .fields = &enumFields,
29
+ .decls = &decls,
30
+ .is_exhaustive = true,
31
+ },
32
+ });
33
+ }
34
+
35
+ test Optional {
36
+ try expect(@bitSizeOf(Optional(bool)) == 2);
37
+
38
+ const a: Optional(bool) = .true;
39
+ try expect(a != .None);
40
+ try expect(a == .true);
41
+ try expect(a != .false);
42
+
43
+ const b: Optional(bool) = .None;
44
+ try expect(b == .None);
45
+ try expect(b != .true);
46
+ try expect(b != .false);
47
+
48
+ const Player = @import("./data.zig").Player;
49
+ try expect(@bitSizeOf(Optional(Player)) == 2);
50
+
51
+ const p: Optional(Player) = .P2;
52
+ try expect(p != .None);
53
+ try expect(p != .P1);
54
+ try expect(p == .P2);
55
+
56
+ const q: Optional(Player) = .None;
57
+ try expect(q == .None);
58
+ try expect(q != .P1);
59
+ try expect(q != .P2);
60
+ }
@@ -1,11 +1,15 @@
1
1
  const build_options = @import("build_options");
2
2
  const root = @import("root");
3
3
 
4
+ /// Configures the behavior of the pkmn package.
4
5
  pub const Options = struct {
5
6
  showdown: ?bool = null,
6
7
  log: ?bool = null,
8
+ chance: ?bool = null,
9
+ calc: ?bool = null,
7
10
  advance: ?bool = null,
8
11
  ebc: ?bool = null,
12
+ key: ?bool = null,
9
13
  internal: ?bool = null,
10
14
  };
11
15
 
@@ -13,9 +17,14 @@ pub const Options = struct {
13
17
  pub const showdown = get("showdown", false);
14
18
  /// Whether or not protocol message logging is enabled.
15
19
  pub const log = get("log", false);
20
+ /// Whether or not update probability tracking is enabled.
21
+ pub const chance = get("chance", false);
22
+ /// Whether or not damage calculator support is enabled.
23
+ pub const calc = get("calc", false);
16
24
 
17
25
  pub const advance = get("advance", true);
18
26
  pub const ebc = get("ebc", true);
27
+ pub const key = get("key", false);
19
28
  pub const internal = get("internal", false);
20
29
 
21
30
  fn get(comptime name: []const u8, default: bool) bool {
@@ -102,6 +102,9 @@ pub const ArgType = enum(u8) {
102
102
  // Gen 8
103
103
  CanDynamax,
104
104
  SwapSideConditions,
105
+
106
+ // Gen 9
107
+ Terastallize,
105
108
  };
106
109
 
107
110
  pub const Move = enum(u8) {
@@ -219,8 +222,12 @@ pub const Immune = enum(u8) {
219
222
  OHKO,
220
223
  };
221
224
 
225
+ /// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
226
+ /// Ignores anything sent to it, though protocol logging should additionally be turned off
227
+ /// entirely with `options.log`.
222
228
  pub const NULL = Log(@TypeOf(std.io.null_writer)){ .writer = std.io.null_writer };
223
229
 
230
+ /// Logs protocol information to its `Writer` during a battle update when `options.log` is enabled.
224
231
  pub fn Log(comptime Writer: type) type {
225
232
  return struct {
226
233
  const Self = @This();
@@ -231,6 +238,7 @@ pub fn Log(comptime Writer: type) type {
231
238
 
232
239
  pub fn move(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
233
240
  if (!enabled) return;
241
+
234
242
  assert(m != .None);
235
243
  try self.writer.writeAll(&.{
236
244
  @intFromEnum(ArgType.Move),
@@ -254,6 +262,7 @@ pub fn Log(comptime Writer: type) type {
254
262
 
255
263
  pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
256
264
  if (!enabled) return;
265
+
257
266
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
258
267
  try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
259
268
  try self.writer.writeIntNative(u16, pokemon.hp);
@@ -263,6 +272,7 @@ pub fn Log(comptime Writer: type) type {
263
272
 
264
273
  pub fn cant(self: Self, ident: ID, reason: Cant) Error!void {
265
274
  if (!enabled) return;
275
+
266
276
  assert(reason != .Disable);
267
277
  try self.writer.writeAll(&.{
268
278
  @intFromEnum(ArgType.Cant),
@@ -273,6 +283,7 @@ pub fn Log(comptime Writer: type) type {
273
283
 
274
284
  pub fn disabled(self: Self, ident: ID, m: anytype) Error!void {
275
285
  if (!enabled) return;
286
+
276
287
  try self.writer.writeAll(&.{
277
288
  @intFromEnum(ArgType.Cant),
278
289
  @as(u8, @bitCast(ident)),
@@ -283,12 +294,14 @@ pub fn Log(comptime Writer: type) type {
283
294
 
284
295
  pub fn faint(self: Self, ident: ID, done: bool) Error!void {
285
296
  if (!enabled) return;
297
+
286
298
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(ident)) });
287
299
  if (done) try self.writer.writeByte(@intFromEnum(ArgType.None));
288
300
  }
289
301
 
290
302
  pub fn turn(self: Self, num: u16) Error!void {
291
303
  if (!enabled) return;
304
+
292
305
  try self.writer.writeByte(@intFromEnum(ArgType.Turn));
293
306
  try self.writer.writeIntNative(u16, num);
294
307
  try self.writer.writeByte(@intFromEnum(ArgType.None));
@@ -296,6 +309,7 @@ pub fn Log(comptime Writer: type) type {
296
309
 
297
310
  pub fn win(self: Self, player: Player) Error!void {
298
311
  if (!enabled) return;
312
+
299
313
  try self.writer.writeAll(&.{
300
314
  @intFromEnum(ArgType.Win),
301
315
  @intFromEnum(player),
@@ -305,11 +319,13 @@ pub fn Log(comptime Writer: type) type {
305
319
 
306
320
  pub fn tie(self: Self) Error!void {
307
321
  if (!enabled) return;
322
+
308
323
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Tie), @intFromEnum(ArgType.None) });
309
324
  }
310
325
 
311
326
  pub fn damage(self: Self, ident: ID, pokemon: anytype, reason: Damage) Error!void {
312
327
  if (!enabled) return;
328
+
313
329
  assert(@intFromEnum(reason) <= @intFromEnum(Damage.LeechSeed));
314
330
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
315
331
  try self.writer.writeIntNative(u16, pokemon.hp);
@@ -325,6 +341,7 @@ pub fn Log(comptime Writer: type) type {
325
341
  source: ID,
326
342
  ) Error!void {
327
343
  if (!enabled) return;
344
+
328
345
  assert(@intFromEnum(reason) == @intFromEnum(Damage.RecoilOf));
329
346
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
330
347
  try self.writer.writeIntNative(u16, pokemon.hp);
@@ -338,6 +355,7 @@ pub fn Log(comptime Writer: type) type {
338
355
 
339
356
  pub fn heal(self: Self, ident: ID, pokemon: anytype, reason: Heal) Error!void {
340
357
  if (!enabled) return;
358
+
341
359
  assert(reason != .Drain);
342
360
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(ident)) });
343
361
  try self.writer.writeIntNative(u16, pokemon.hp);
@@ -347,6 +365,7 @@ pub fn Log(comptime Writer: type) type {
347
365
 
348
366
  pub fn drain(self: Self, source: ID, pokemon: anytype, target: ID) Error!void {
349
367
  if (!enabled) return;
368
+
350
369
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(source)) });
351
370
  try self.writer.writeIntNative(u16, pokemon.hp);
352
371
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
@@ -359,6 +378,7 @@ pub fn Log(comptime Writer: type) type {
359
378
 
360
379
  pub fn status(self: Self, ident: ID, value: u8, reason: Status) Error!void {
361
380
  if (!enabled) return;
381
+
362
382
  assert(reason != .From);
363
383
  try self.writer.writeAll(&.{
364
384
  @intFromEnum(ArgType.Status),
@@ -370,6 +390,7 @@ pub fn Log(comptime Writer: type) type {
370
390
 
371
391
  pub fn statusFrom(self: Self, ident: ID, value: u8, m: anytype) Error!void {
372
392
  if (!enabled) return;
393
+
373
394
  try self.writer.writeAll(&.{
374
395
  @intFromEnum(ArgType.Status),
375
396
  @as(u8, @bitCast(ident)),
@@ -381,6 +402,7 @@ pub fn Log(comptime Writer: type) type {
381
402
 
382
403
  pub fn curestatus(self: Self, ident: ID, value: u8, reason: CureStatus) Error!void {
383
404
  if (!enabled) return;
405
+
384
406
  try self.writer.writeAll(&.{
385
407
  @intFromEnum(ArgType.CureStatus),
386
408
  @as(u8, @bitCast(ident)),
@@ -391,6 +413,7 @@ pub fn Log(comptime Writer: type) type {
391
413
 
392
414
  pub fn boost(self: Self, ident: ID, reason: Boost, num: i8) Error!void {
393
415
  if (!enabled) return;
416
+
394
417
  assert(num != 0 and (reason != .Rage or num > 0));
395
418
  try self.writer.writeAll(&.{
396
419
  @intFromEnum(ArgType.Boost),
@@ -402,11 +425,13 @@ pub fn Log(comptime Writer: type) type {
402
425
 
403
426
  pub fn clearallboost(self: Self) Error!void {
404
427
  if (!enabled) return;
428
+
405
429
  try self.writer.writeAll(&.{@intFromEnum(ArgType.ClearAllBoost)});
406
430
  }
407
431
 
408
432
  pub fn fail(self: Self, ident: ID, reason: Fail) Error!void {
409
433
  if (!enabled) return;
434
+
410
435
  try self.writer.writeAll(&.{
411
436
  @intFromEnum(ArgType.Fail),
412
437
  @as(u8, @bitCast(ident)),
@@ -416,11 +441,13 @@ pub fn Log(comptime Writer: type) type {
416
441
 
417
442
  pub fn miss(self: Self, source: ID) Error!void {
418
443
  if (!enabled) return;
444
+
419
445
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(source)) });
420
446
  }
421
447
 
422
448
  pub fn hitcount(self: Self, ident: ID, num: u8) Error!void {
423
449
  if (!enabled) return;
450
+
424
451
  try self.writer.writeAll(&.{
425
452
  @intFromEnum(ArgType.HitCount),
426
453
  @as(u8, @bitCast(ident)),
@@ -430,6 +457,7 @@ pub fn Log(comptime Writer: type) type {
430
457
 
431
458
  pub fn prepare(self: Self, source: ID, m: anytype) Error!void {
432
459
  if (!enabled) return;
460
+
433
461
  try self.writer.writeAll(&.{
434
462
  @intFromEnum(ArgType.Prepare),
435
463
  @as(u8, @bitCast(source)),
@@ -439,6 +467,7 @@ pub fn Log(comptime Writer: type) type {
439
467
 
440
468
  pub fn mustrecharge(self: Self, ident: ID) Error!void {
441
469
  if (!enabled) return;
470
+
442
471
  try self.writer.writeAll(&.{
443
472
  @intFromEnum(ArgType.MustRecharge),
444
473
  @as(u8, @bitCast(ident)),
@@ -447,6 +476,7 @@ pub fn Log(comptime Writer: type) type {
447
476
 
448
477
  pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
449
478
  if (!enabled) return;
479
+
450
480
  try self.writer.writeAll(&.{
451
481
  @intFromEnum(ArgType.Activate),
452
482
  @as(u8, @bitCast(ident)),
@@ -456,11 +486,13 @@ pub fn Log(comptime Writer: type) type {
456
486
 
457
487
  pub fn fieldactivate(self: Self) Error!void {
458
488
  if (!enabled) return;
489
+
459
490
  try self.writer.writeAll(&.{@intFromEnum(ArgType.FieldActivate)});
460
491
  }
461
492
 
462
493
  pub fn start(self: Self, ident: ID, reason: Start) Error!void {
463
494
  if (!enabled) return;
495
+
464
496
  assert(@intFromEnum(reason) < @intFromEnum(Start.TypeChange));
465
497
  try self.writer.writeAll(&.{
466
498
  @intFromEnum(ArgType.Start),
@@ -471,6 +503,7 @@ pub fn Log(comptime Writer: type) type {
471
503
 
472
504
  pub fn typechange(self: Self, source: ID, types: anytype, target: ID) Error!void {
473
505
  if (!enabled) return;
506
+
474
507
  try self.writer.writeAll(&.{
475
508
  @intFromEnum(ArgType.Start),
476
509
  @as(u8, @bitCast(source)),
@@ -482,6 +515,7 @@ pub fn Log(comptime Writer: type) type {
482
515
 
483
516
  pub fn startEffect(self: Self, ident: ID, reason: Start, m: anytype) Error!void {
484
517
  if (!enabled) return;
518
+
485
519
  assert(@intFromEnum(reason) > @intFromEnum(Start.TypeChange));
486
520
  try self.writer.writeAll(&.{
487
521
  @intFromEnum(ArgType.Start),
@@ -493,6 +527,7 @@ pub fn Log(comptime Writer: type) type {
493
527
 
494
528
  pub fn end(self: Self, ident: ID, reason: End) Error!void {
495
529
  if (!enabled) return;
530
+
496
531
  try self.writer.writeAll(&.{
497
532
  @intFromEnum(ArgType.End),
498
533
  @as(u8, @bitCast(ident)),
@@ -502,16 +537,19 @@ pub fn Log(comptime Writer: type) type {
502
537
 
503
538
  pub fn ohko(self: Self) Error!void {
504
539
  if (!enabled) return;
540
+
505
541
  try self.writer.writeAll(&.{@intFromEnum(ArgType.OHKO)});
506
542
  }
507
543
 
508
544
  pub fn crit(self: Self, ident: ID) Error!void {
509
545
  if (!enabled) return;
546
+
510
547
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(ident)) });
511
548
  }
512
549
 
513
550
  pub fn supereffective(self: Self, ident: ID) Error!void {
514
551
  if (!enabled) return;
552
+
515
553
  try self.writer.writeAll(&.{
516
554
  @intFromEnum(ArgType.SuperEffective),
517
555
  @as(u8, @bitCast(ident)),
@@ -520,6 +558,7 @@ pub fn Log(comptime Writer: type) type {
520
558
 
521
559
  pub fn resisted(self: Self, ident: ID) Error!void {
522
560
  if (!enabled) return;
561
+
523
562
  try self.writer.writeAll(&.{
524
563
  @intFromEnum(ArgType.Resisted),
525
564
  @as(u8, @bitCast(ident)),
@@ -528,6 +567,7 @@ pub fn Log(comptime Writer: type) type {
528
567
 
529
568
  pub fn immune(self: Self, ident: ID, reason: Immune) Error!void {
530
569
  if (!enabled) return;
570
+
531
571
  try self.writer.writeAll(&.{
532
572
  @intFromEnum(ArgType.Immune),
533
573
  @as(u8, @bitCast(ident)),
@@ -537,6 +577,7 @@ pub fn Log(comptime Writer: type) type {
537
577
 
538
578
  pub fn transform(self: Self, source: ID, target: ID) Error!void {
539
579
  if (!enabled) return;
580
+
540
581
  try self.writer.writeAll(&.{
541
582
  @intFromEnum(ArgType.Transform),
542
583
  @as(u8, @bitCast(source)),
@@ -546,18 +587,24 @@ pub fn Log(comptime Writer: type) type {
546
587
 
547
588
  pub fn laststill(self: Self) Error!void {
548
589
  if (!enabled) return;
590
+
549
591
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastStill)});
550
592
  }
551
593
 
552
594
  pub fn lastmiss(self: Self) Error!void {
553
595
  if (!enabled) return;
596
+
554
597
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastMiss)});
555
598
  }
556
599
  };
557
600
  }
558
601
 
602
+ /// `Log` type backed by the optimized `ByteStream.Writer`.
559
603
  pub const FixedLog = Log(ByteStream.Writer);
560
604
 
605
+ /// Stripped down version of `std.io.FixedBufferStream` optimized for efficiently writing the
606
+ /// individual protocol bytes. Note that the `ByteStream.Writer` is **not** a `std.io.Writer` and
607
+ /// should not be used for general purpose writing.
561
608
  pub const ByteStream = struct {
562
609
  buffer: []u8,
563
610
  pos: usize = 0,
@@ -855,6 +902,7 @@ pub fn expectLog(
855
902
  offset: usize,
856
903
  ) !void {
857
904
  if (!enabled) return;
905
+
858
906
  const color = color: {
859
907
  if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
860
908
  break :color true;