1- /// Generates bytes.
1+ //! Generates bytes.
22const Bytes = @This ();
33
44const std = @import ("std" );
@@ -7,54 +7,180 @@ const Generator = @import("Generator.zig");
77/// Random number generator.
88rand : std.Random ,
99
10- /// The minimum and maximum length of the generated bytes. The maximum
11- /// length will be capped to the length of the buffer passed in if the
12- /// buffer length is smaller.
13- min_len : usize = 1 ,
14- max_len : usize = std .math .maxInt (usize ),
10+ /// The minimum and maximum length of the generated bytes.
11+ _min_len : usize = 1 ,
12+ _max_len : usize = std .math .maxInt (usize ),
1513
1614/// The possible bytes that can be generated. If a byte is duplicated
1715/// in the alphabet, it will be more likely to be generated. That's a
1816/// side effect of the generator, not an intended use case.
19- alphabet : ? []const u8 = null ,
17+ _alphabet : ? []const u8 = null ,
2018
2119/// Predefined alphabets.
2220pub const Alphabet = struct {
23- pub const ascii = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;':\\ \" ,./<>?`~" ;
21+ fn _generate (comptime func : fn (u8 ) bool ) []const u8 {
22+ @setEvalBranchQuota (3000 );
23+ var count = 0 ;
24+ for (0.. 256) | c | {
25+ if (func (c )) count += 1 ;
26+ }
27+ var _alphabet : [count ]u8 = undefined ;
28+ var i = 0 ;
29+ for (0.. 256) | c | {
30+ if (func (c )) {
31+ _alphabet [i ] = c ;
32+ i += 1 ;
33+ }
34+ }
35+ const result = _alphabet ;
36+ return & result ;
37+ }
38+
39+ fn _ascii (c : u8 ) bool {
40+ return switch (c ) {
41+ ' ' = > false ,
42+ else = > std .ascii .isPrint (c ),
43+ };
44+ }
45+
46+ pub const ascii = _generate (_ascii );
47+ pub const alphanumeric = _generate (std .ascii .isAlphanumeric );
48+ pub const alphabetic = _generate (std .ascii .isAlphabetic );
49+
50+ fn _kv (c : u8 ) bool {
51+ return switch (c ) {
52+ std .ascii .control_code .esc , std .ascii .control_code .bel , ';' , '=' = > false ,
53+ else = > std .ascii .isPrint (c ),
54+ };
55+ }
56+
57+ /// The alphabet for random bytes in OSC key/value pairs (omitting 0x1B,
58+ /// 0x07, ';', '=').
59+ pub const kv = _generate (_kv );
60+
61+ fn _osc (c : u8 ) bool {
62+ return switch (c ) {
63+ std .ascii .control_code .esc , std .ascii .control_code .bel = > false ,
64+ else = > true ,
65+ };
66+ }
67+
68+ /// The alphabet for random bytes in OSCs (omitting 0x1B and 0x07).
69+ pub const osc = _generate (_osc );
70+
71+ pub const Keys = keys : {
72+ const decls = @typeInfo (Alphabet ).@"struct" .decls ;
73+ var count = 0 ;
74+ for (decls ) | decl | {
75+ if (std .mem .eql (u8 , decl .name , "Keys" )) continue ;
76+ if (decl .name [0 ] == '_' ) continue ;
77+ count += 1 ;
78+ }
79+ var fields : [count ]std.builtin.Type.EnumField = undefined ;
80+ var i = 0 ;
81+ for (decls ) | decl | {
82+ if (std .mem .eql (u8 , decl .name , "Keys" )) continue ;
83+ if (decl .name [0 ] == '_' ) continue ;
84+ fields [i ].name = decl .name ;
85+ fields [i ].value = i ;
86+ i += 1 ;
87+ }
88+ break :keys @Type (
89+ .{
90+ .@"enum" = .{
91+ .fields = & fields ,
92+ .decls = &.{},
93+ .is_exhaustive = true ,
94+ .tag_type = std .math .IntFittingRange (0 , count ),
95+ },
96+ },
97+ );
98+ };
2499};
25100
26101pub fn generator (self : * Bytes ) Generator {
27102 return .init (self , next );
28103}
29104
30- pub fn next (self : * Bytes , writer : * std.Io.Writer , max_len : usize ) Generator.Error ! void {
31- std .debug .assert (max_len >= 1 );
32- const len = @min (
33- self .rand .intRangeAtMostBiased (usize , self .min_len , self .max_len ),
34- max_len ,
35- );
105+ pub fn init (rand : std.Random ) Bytes {
106+ return .{
107+ .rand = rand ,
108+ };
109+ }
110+
111+ pub fn next (self : * const Bytes , writer : * std.Io.Writer , max_len : usize ) std.Io.Writer.Error ! void {
112+ try self .atMost (max_len ).format (writer );
113+ }
114+
115+ /// Return a copy of the Bytes, but with a new alphabet.
116+ pub fn alphabet (self : * const Bytes , comptime key : Alphabet.Keys ) Bytes {
117+ return .{
118+ ._alphabet = @field (Alphabet , @tagName (key )),
119+ ._min_len = self ._min_len ,
120+ ._max_len = self ._max_len ,
121+ .rand = self .rand ,
122+ };
123+ }
124+
125+ /// Return a copy of the Bytes, but with a new min_len. The new min
126+ /// len cannot be more than the previous max_len.
127+ pub fn atLeast (self : * const Bytes , min_len : usize ) Bytes {
128+ return .{
129+ .rand = self .rand ,
130+ ._alphabet = self ._alphabet ,
131+ ._min_len = @min (self ._max_len , min_len ),
132+ ._max_len = self ._max_len ,
133+ };
134+ }
135+
136+ /// Return a copy of the Bytes, but with a new max_len. The new max_len cannot
137+ /// be more the previous max_len.
138+ pub fn atMost (self : * const Bytes , max_len : usize ) Bytes {
139+ return .{
140+ .rand = self .rand ,
141+ ._alphabet = self ._alphabet ,
142+ ._min_len = @min (self ._min_len , @min (self ._max_len , max_len )),
143+ ._max_len = @min (self ._max_len , max_len ),
144+ };
145+ }
146+
147+ pub fn format (self : * const Bytes , writer : * std.Io.Writer ) std.Io.Writer.Error ! void {
148+ _ = try self .write (writer );
149+ }
150+
151+ /// Write some random data and return the number of bytes written.
152+ pub fn write (self : * const Bytes , writer : * std.Io.Writer ) std.Io.Writer.Error ! usize {
153+ std .debug .assert (self ._min_len >= 1 );
154+ std .debug .assert (self ._max_len >= self ._min_len );
155+
156+ const len = self .rand .intRangeAtMostBiased (usize , self ._min_len , self ._max_len );
36157
37158 var buf : [8 ]u8 = undefined ;
159+
38160 var remaining = len ;
39161 while (remaining > 0 ) {
40162 const data = buf [0.. @min (remaining , buf .len )];
41163 self .rand .bytes (data );
42- if (self .alphabet ) | alphabet | {
43- for (data ) | * byte | byte .* = alphabet [byte .* % alphabet .len ];
164+ if (self ._alphabet ) | _alphabet | {
165+ for (data ) | * byte | byte .* = _alphabet [byte .* % _alphabet .len ];
44166 }
45167 try writer .writeAll (data );
46168 remaining -= data .len ;
47169 }
170+
171+ return len ;
48172}
49173
50174test "bytes" {
51175 const testing = std .testing ;
52176 var prng = std .Random .DefaultPrng .init (0 );
53177 var buf : [256 ]u8 = undefined ;
54178 var writer : std.Io.Writer = .fixed (& buf );
55- var v : Bytes = .{ .rand = prng .random () };
56- v .min_len = buf .len ;
57- v .max_len = buf .len ;
179+ var v : Bytes = .{
180+ .rand = prng .random (),
181+ ._min_len = buf .len ,
182+ ._max_len = buf .len ,
183+ };
58184 const gen = v .generator ();
59185 try gen .next (& writer , buf .len );
60186 try testing .expectEqual (buf .len , writer .buffered ().len );
0 commit comments