mirror-ghostty/src/synthetic/Bytes.zig

62 lines
1.9 KiB
Zig

/// Generates bytes.
const Bytes = @This();
const std = @import("std");
const Generator = @import("Generator.zig");
/// Random number generator.
rand: std.Random,
/// The minimum and maximum length of the generated bytes. The maximum
/// length will be capped to the length of the buffer passed in if the
/// buffer length is smaller.
min_len: usize = 1,
max_len: usize = std.math.maxInt(usize),
/// The possible bytes that can be generated. If a byte is duplicated
/// in the alphabet, it will be more likely to be generated. That's a
/// side effect of the generator, not an intended use case.
alphabet: ?[]const u8 = null,
/// Predefined alphabets.
pub const Alphabet = struct {
pub const ascii = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;':\\\",./<>?`~";
};
pub fn generator(self: *Bytes) Generator {
return .init(self, next);
}
pub fn next(self: *Bytes, writer: *std.Io.Writer, max_len: usize) Generator.Error!void {
std.debug.assert(max_len >= 1);
const len = @min(
self.rand.intRangeAtMostBiased(usize, self.min_len, self.max_len),
max_len,
);
var buf: [8]u8 = undefined;
var remaining = len;
while (remaining > 0) {
const data = buf[0..@min(remaining, buf.len)];
self.rand.bytes(data);
if (self.alphabet) |alphabet| {
for (data) |*byte| byte.* = alphabet[byte.* % alphabet.len];
}
try writer.writeAll(data);
remaining -= data.len;
}
}
test "bytes" {
const testing = std.testing;
var prng = std.Random.DefaultPrng.init(0);
var buf: [256]u8 = undefined;
var writer: std.Io.Writer = .fixed(&buf);
var v: Bytes = .{ .rand = prng.random() };
v.min_len = buf.len;
v.max_len = buf.len;
const gen = v.generator();
try gen.next(&writer, buf.len);
try testing.expectEqual(buf.len, writer.buffered().len);
}