Skip to content

Commit f838349

Browse files
Vexuandrewrk
authored andcommitted
std: collect all options under one namespace
1 parent fe2bd9d commit f838349

17 files changed

Lines changed: 164 additions & 97 deletions

File tree

lib/std/crypto/tlcsprng.zig

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
const std = @import("std");
77
const builtin = @import("builtin");
8-
const root = @import("root");
98
const mem = std.mem;
109
const os = std.os;
1110

@@ -67,8 +66,8 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
6766
// Allow applications to decide they would prefer to have every call to
6867
// std.crypto.random always make an OS syscall, rather than rely on an
6968
// application implementation of a CSPRNG.
70-
if (comptime std.meta.globalOption("crypto_always_getrandom", bool) orelse false) {
71-
return fillWithOsEntropy(buffer);
69+
if (std.options.crypto_always_getrandom) {
70+
return defaultRandomSeed(buffer);
7271
}
7372

7473
if (wipe_mem.len == 0) {
@@ -86,7 +85,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
8685
) catch {
8786
// Could not allocate memory for the local state, fall back to
8887
// the OS syscall.
89-
return fillWithOsEntropy(buffer);
88+
return std.options.cryptoRandomSeed(buffer);
9089
};
9190
// The memory is already zero-initialized.
9291
} else {
@@ -128,14 +127,14 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
128127
// Since we failed to set up fork safety, we fall back to always
129128
// calling getrandom every time.
130129
ctx.init_state = .failed;
131-
return fillWithOsEntropy(buffer);
130+
return std.options.cryptoRandomSeed(buffer);
132131
},
133132
.initialized => {
134133
return fillWithCsprng(buffer);
135134
},
136135
.failed => {
137136
if (want_fork_safety) {
138-
return fillWithOsEntropy(buffer);
137+
return std.options.cryptoRandomSeed(buffer);
139138
} else {
140139
unreachable;
141140
}
@@ -165,7 +164,7 @@ fn fillWithCsprng(buffer: []u8) void {
165164
mem.set(u8, ctx.gimli.toSlice()[0..std.crypto.core.Gimli.RATE], 0);
166165
}
167166

168-
fn fillWithOsEntropy(buffer: []u8) void {
167+
pub fn defaultRandomSeed(buffer: []u8) void {
169168
os.getrandom(buffer) catch @panic("getrandom() failed to provide entropy");
170169
}
171170

@@ -174,12 +173,8 @@ fn initAndFill(buffer: []u8) void {
174173
// Because we panic on getrandom() failing, we provide the opportunity
175174
// to override the default seed function. This also makes
176175
// `std.crypto.random` available on freestanding targets, provided that
177-
// the `cryptoRandomSeed` function is provided.
178-
if (@hasDecl(root, "cryptoRandomSeed")) {
179-
root.cryptoRandomSeed(&seed);
180-
} else {
181-
fillWithOsEntropy(&seed);
182-
}
176+
// the `std.options.cryptoRandomSeed` function is provided.
177+
std.options.cryptoRandomSeed(&seed);
183178

184179
const ctx = @ptrCast(*Context, wipe_mem.ptr);
185180
ctx.gimli = std.crypto.core.Gimli.init(seed);

lib/std/debug.zig

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,10 +1861,9 @@ pub const have_segfault_handling_support = switch (native_os) {
18611861
.freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"),
18621862
else => false,
18631863
};
1864-
pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
1865-
root.enable_segfault_handler
1866-
else
1867-
runtime_safety and have_segfault_handling_support;
1864+
1865+
const enable_segfault_handler = std.options.enable_segfault_handler;
1866+
pub const default_enable_segfault_handler = runtime_safety and have_segfault_handling_support;
18681867

18691868
pub fn maybeEnableSegfaultHandler() void {
18701869
if (enable_segfault_handler) {

lib/std/event/batch.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn Batch(
1717
comptime async_behavior: enum {
1818
/// Observe the value of `std.io.is_async` to decide whether `add`
1919
/// and `wait` will be async functions. Asserts that the jobs do not suspend when
20-
/// `std.io.mode == .blocking`. This is a generally safe assumption, and the
20+
/// `std.options.io_mode == .blocking`. This is a generally safe assumption, and the
2121
/// usual recommended option for this parameter.
2222
auto_async,
2323

lib/std/event/loop.zig

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const std = @import("../std.zig");
22
const builtin = @import("builtin");
3-
const root = @import("root");
43
const assert = std.debug.assert;
54
const testing = std.testing;
65
const mem = std.mem;
@@ -104,25 +103,29 @@ pub const Loop = struct {
104103
};
105104
};
106105

107-
const LoopOrVoid = switch (std.io.mode) {
108-
.blocking => void,
109-
.evented => Loop,
106+
pub const Instance = switch (std.options.io_mode) {
107+
.blocking => @TypeOf(null),
108+
.evented => ?*Loop,
110109
};
110+
pub const instance = std.options.event_loop;
111111

112-
var global_instance_state: LoopOrVoid = undefined;
113-
const default_instance: ?*LoopOrVoid = switch (std.io.mode) {
112+
var global_instance_state: Loop = undefined;
113+
pub const default_instance = switch (std.options.io_mode) {
114114
.blocking => null,
115115
.evented => &global_instance_state,
116116
};
117-
pub const instance: ?*LoopOrVoid = if (@hasDecl(root, "event_loop")) root.event_loop else default_instance;
117+
118+
pub const Mode = enum {
119+
single_threaded,
120+
multi_threaded,
121+
};
122+
pub const default_mode = .multi_threaded;
118123

119124
/// TODO copy elision / named return values so that the threads referencing *Loop
120125
/// have the correct pointer value.
121126
/// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
122127
pub fn init(self: *Loop) !void {
123-
if (builtin.single_threaded or
124-
(@hasDecl(root, "event_loop_mode") and root.event_loop_mode == .single_threaded))
125-
{
128+
if (builtin.single_threaded or std.options.event_loop_mode == .single_threaded) {
126129
return self.initSingleThreaded();
127130
} else {
128131
return self.initMultiThreaded();

lib/std/fs.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2661,17 +2661,17 @@ pub fn cwd() Dir {
26612661
if (builtin.os.tag == .windows) {
26622662
return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
26632663
} else if (builtin.os.tag == .wasi) {
2664-
if (@hasDecl(root, "wasi_cwd")) {
2665-
return root.wasi_cwd();
2666-
} else {
2667-
// Expect the first preopen to be current working directory.
2668-
return .{ .fd = 3 };
2669-
}
2664+
return std.options.wasiCwd();
26702665
} else {
26712666
return Dir{ .fd = os.AT.FDCWD };
26722667
}
26732668
}
26742669

2670+
pub fn defaultWasiCwd() Dir {
2671+
// Expect the first preopen to be current working directory.
2672+
return .{ .fd = 3 };
2673+
}
2674+
26752675
/// Opens a directory at the given path. The directory is a system resource that remains
26762676
/// open until `close` is called on the result.
26772677
/// See `openDirAbsoluteZ` for a function that accepts a null-terminated path.

lib/std/fs/file.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub const File = struct {
2121
/// blocking.
2222
capable_io_mode: io.ModeOverride = io.default_mode,
2323

24-
/// Furthermore, even when `std.io.mode` is async, it is still sometimes desirable
24+
/// Furthermore, even when `std.options.io_mode` is async, it is still sometimes desirable
2525
/// to perform blocking I/O, although not by default. For example, when printing a
2626
/// stack trace to stderr. This field tracks both by acting as an overriding I/O mode.
2727
/// When not building in async I/O mode, the type only has the `.blocking` tag, making

lib/std/io.zig

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,7 @@ pub const Mode = enum {
1919
evented,
2020
};
2121

22-
/// The application's chosen I/O mode. This defaults to `Mode.blocking` but can be overridden
23-
/// by `root.event_loop`.
24-
pub const mode: Mode = if (@hasDecl(root, "io_mode"))
25-
root.io_mode
26-
else if (@hasDecl(root, "event_loop"))
27-
Mode.evented
28-
else
29-
Mode.blocking;
22+
const mode = std.options.io_mode;
3023
pub const is_async = mode != .blocking;
3124

3225
/// This is an enum value to use for I/O mode at runtime, since it takes up zero bytes at runtime,

lib/std/log.zig

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! std.log is a standardized interface for logging which allows for the logging
22
//! of programs and libraries using this interface to be formatted and filtered
3-
//! by the implementer of the root.log function.
3+
//! by the implementer of the `std.options.logFn` function.
44
//!
55
//! Each log message has an associated scope enum, which can be used to give
66
//! context to the logging. The logging functions in std.log implicitly use a
@@ -13,16 +13,20 @@
1313
//! `const log = std.log.scoped(.libfoo);` to use .libfoo as the scope of its
1414
//! log messages.
1515
//!
16-
//! An example root.log might look something like this:
16+
//! An example `logFn` might look something like this:
1717
//!
1818
//! ```
1919
//! const std = @import("std");
2020
//!
21-
//! // Set the log level to info
22-
//! pub const log_level: std.log.Level = .info;
21+
//! pub const std_options = struct {
22+
//! // Set the log level to info
23+
//! pub const log_level = .info;
2324
//!
24-
//! // Define root.log to override the std implementation
25-
//! pub fn log(
25+
//! // Define logFn to override the std implementation
26+
//! pub const logFn = myLogFn;
27+
//! };
28+
//!
29+
//! pub fn myLogFn(
2630
//! comptime level: std.log.Level,
2731
//! comptime scope: @TypeOf(.EnumLiteral),
2832
//! comptime format: []const u8,
@@ -70,7 +74,6 @@
7074

7175
const std = @import("std.zig");
7276
const builtin = @import("builtin");
73-
const root = @import("root");
7477

7578
pub const Level = enum {
7679
/// Error: something has gone wrong. This might be recoverable or might
@@ -102,22 +105,14 @@ pub const default_level: Level = switch (builtin.mode) {
102105
.ReleaseFast, .ReleaseSmall => .err,
103106
};
104107

105-
/// The current log level. This is set to root.log_level if present, otherwise
106-
/// log.default_level.
107-
pub const level: Level = if (@hasDecl(root, "log_level"))
108-
root.log_level
109-
else
110-
default_level;
108+
const level = std.options.log_level;
111109

112110
pub const ScopeLevel = struct {
113111
scope: @Type(.EnumLiteral),
114112
level: Level,
115113
};
116114

117-
const scope_levels = if (@hasDecl(root, "scope_levels"))
118-
root.scope_levels
119-
else
120-
[0]ScopeLevel{};
115+
const scope_levels = std.options.log_scope_levels;
121116

122117
fn log(
123118
comptime message_level: Level,
@@ -127,13 +122,7 @@ fn log(
127122
) void {
128123
if (comptime !logEnabled(message_level, scope)) return;
129124

130-
if (@hasDecl(root, "log")) {
131-
if (@typeInfo(@TypeOf(root.log)) != .Fn)
132-
@compileError("Expected root.log to be a function");
133-
root.log(message_level, scope, format, args);
134-
} else {
135-
defaultLog(message_level, scope, format, args);
136-
}
125+
std.options.logFn(message_level, scope, format, args);
137126
}
138127

139128
/// Determine if a specific log message level and scope combination are enabled for logging.
@@ -149,8 +138,8 @@ pub fn defaultLogEnabled(comptime message_level: Level) bool {
149138
return comptime logEnabled(message_level, default_log_scope);
150139
}
151140

152-
/// The default implementation for root.log. root.log may forward log messages
153-
/// to this function.
141+
/// The default implementation for the log function, custom log functions may
142+
/// forward log messages to this function.
154143
pub fn defaultLog(
155144
comptime message_level: Level,
156145
comptime scope: @Type(.EnumLiteral),

lib/std/start.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret
527527
// and we want fewer call frames in stack traces.
528528
inline fn initEventLoopAndCallMain() u8 {
529529
if (std.event.Loop.instance) |loop| {
530-
if (!@hasDecl(root, "event_loop")) {
530+
if (loop == std.event.Loop.default_instance) {
531531
loop.init() catch |err| {
532532
std.log.err("{s}", .{@errorName(err)});
533533
if (@errorReturnTrace()) |trace| {
@@ -556,7 +556,7 @@ inline fn initEventLoopAndCallMain() u8 {
556556
// because it is working around stage1 compiler bugs.
557557
inline fn initEventLoopAndCallWinMain() std.os.windows.INT {
558558
if (std.event.Loop.instance) |loop| {
559-
if (!@hasDecl(root, "event_loop")) {
559+
if (loop == std.event.Loop.default_instance) {
560560
loop.init() catch |err| {
561561
std.log.err("{s}", .{@errorName(err)});
562562
if (@errorReturnTrace()) |trace| {

lib/std/std.zig

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,79 @@ pub const wasm = @import("wasm.zig");
9494
pub const zig = @import("zig.zig");
9595
pub const start = @import("start.zig");
9696

97+
const root = @import("root");
98+
const options_override = if (@hasDecl(root, "std_options")) root.std_options else struct {};
99+
100+
pub const options = struct {
101+
pub const enable_segfault_handler: bool = if (@hasDecl(options_override, "enable_segfault_handler"))
102+
options_override.enable_segfault_handler
103+
else
104+
debug.default_enable_segfault_handler;
105+
106+
/// Function used to implement std.fs.cwd for wasi.
107+
pub const wasiCwd: fn () fs.Dir = if (@hasDecl(options_override, "wasiCwd"))
108+
options_override.wasiCwd
109+
else
110+
fs.defaultWasiCwd;
111+
112+
/// The application's chosen I/O mode.
113+
pub const io_mode: io.Mode = if (@hasDecl(options_override, "io_mode"))
114+
options_override.io_mode
115+
else if (@hasDecl(options_override, "event_loop"))
116+
.evented
117+
else
118+
.blocking;
119+
120+
pub const event_loop: event.Loop.Instance = if (@hasDecl(options_override, "event_loop"))
121+
options_override.event_loop
122+
else
123+
event.Loop.default_instance;
124+
125+
pub const event_loop_mode: event.Loop.Mode = if (@hasDecl(options_override, "event_loop_mode"))
126+
options_override.event_loop_mode
127+
else
128+
event.Loop.default_mode;
129+
130+
/// The current log level.
131+
pub const log_level: log.Level = if (@hasDecl(options_override, "log_level"))
132+
options_override.log_level
133+
else
134+
log.default_level;
135+
136+
pub const log_scope_levels: []const log.ScopeLevel = if (@hasDecl(options_override, "log_scope_levels"))
137+
options_override.log_scope_levels
138+
else
139+
&.{};
140+
141+
pub const logFn: fn (
142+
comptime message_level: log.Level,
143+
comptime scope: @TypeOf(.enum_literal),
144+
comptime format: []const u8,
145+
args: anytype,
146+
) void = if (@hasDecl(options_override, "logFn"))
147+
options_override.logFn
148+
else
149+
log.defaultLog;
150+
151+
pub const cryptoRandomSeed: fn (buffer: []u8) void = if (@hasDecl(options_override, "cryptoRandomSeed"))
152+
options_override.cryptoRandomSeed
153+
else
154+
@import("crypto/tlcsprng.zig").defaultRandomSeed;
155+
156+
pub const crypto_always_getrandom: bool = if (@hasDecl(options_override, "crypto_always_getrandom"))
157+
options_override.crypto_always_getrandom
158+
else
159+
false;
160+
};
161+
97162
// This forces the start.zig file to be imported, and the comptime logic inside that
98163
// file decides whether to export any appropriate start symbols, and call main.
99164
comptime {
100165
_ = start;
166+
167+
for (@typeInfo(options_override).Struct.decls) |decl| {
168+
if (!@hasDecl(options, decl.name)) @compileError("no option named " ++ decl.name);
169+
}
101170
}
102171

103172
test {

0 commit comments

Comments
 (0)