windows: use enums for boolean types

This commit is contained in:
Jacob Young
2026-03-18 23:18:35 -04:00
committed by jacobly
parent 30de1678a6
commit 3c8b96df6d
9 changed files with 85 additions and 92 deletions
+2 -2
View File
@@ -345,7 +345,7 @@ const Os = switch (builtin.os.tag) {
.LAST_WRITE = true,
.CREATION = true,
},
windows.FALSE,
.FALSE,
.Notify,
)) {
.SUCCESS, .PENDING => dir.state = .listening,
@@ -632,7 +632,7 @@ const Os = switch (builtin.os.tag) {
.none => std.math.minInt(windows.LARGE_INTEGER),
.ms => |ms| -@as(windows.LARGE_INTEGER, ms) * (std.time.ns_per_ms / 100),
};
_ = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval);
_ = windows.ntdll.NtDelayExecution(.TRUE, &delay_interval);
} else unreachable;
}
},
+35 -37
View File
@@ -1572,7 +1572,7 @@ const AlertableSyscall = struct {
pub fn waitForApcOrAlert() void {
const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
_ = windows.ntdll.NtDelayExecution(windows.TRUE, &infinite_timeout);
_ = windows.ntdll.NtDelayExecution(.TRUE, &infinite_timeout);
}
pub const max_iovecs_len = 8;
@@ -2735,7 +2735,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
break :interval timeoutToWindowsInterval(.{ .deadline = d }).?;
};
const alertable_syscall = try AlertableSyscall.start();
const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval);
const delay_rc = windows.ntdll.NtDelayExecution(.TRUE, &delay_interval);
alertable_syscall.finish();
switch (delay_rc) {
.SUCCESS, .TIMEOUT => {
@@ -4533,8 +4533,8 @@ fn dirCreateFileWindows(
&windows_lock_range_off,
&windows_lock_range_len,
null,
@intFromBool(flags.lock_nonblocking),
@intFromBool(exclusive),
.fromBool(flags.lock_nonblocking),
.fromBool(exclusive),
)) {
.SUCCESS => {
syscall.finish();
@@ -5129,8 +5129,8 @@ pub fn dirOpenFileWtf16(
&windows_lock_range_off,
&windows_lock_range_len,
null,
@intFromBool(flags.lock_nonblocking),
@intFromBool(exclusive),
.fromBool(flags.lock_nonblocking),
.fromBool(exclusive),
)) {
.SUCCESS => break syscall.finish(),
.INSUFFICIENT_RESOURCES => return syscall.fail(error.SystemResources),
@@ -5886,9 +5886,9 @@ fn dirReadWindows(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) D
unreserved_buffer.ptr,
std.math.lossyCast(w.ULONG, unreserved_buffer.len),
.BothDirectory,
w.FALSE,
.FALSE,
null,
@intFromBool(dr.state == .reset),
.fromBool(dr.state == .reset),
)) {
.CANCELLED => {
try syscall.checkCancel();
@@ -7229,9 +7229,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
// Deletion with file pending semantics, which requires waiting or moving
// files to get them removed (from here).
var file_dispo: w.FILE.DISPOSITION.INFORMATION = .{
.DeleteFile = w.TRUE,
};
var file_dispo: w.FILE.DISPOSITION.INFORMATION = .{ .DeleteFile = .TRUE };
while (true) switch (w.ntdll.NtSetInformationFile(
tmp_handle,
@@ -9188,8 +9186,8 @@ fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!v
&windows_lock_range_off,
&windows_lock_range_len,
null,
windows.FALSE,
@intFromBool(exclusive),
.FALSE,
.fromBool(exclusive),
)) {
.SUCCESS => return syscall.finish(),
.CANCELLED => {
@@ -9269,8 +9267,8 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro
&windows_lock_range_off,
&windows_lock_range_len,
null,
windows.TRUE,
@intFromBool(exclusive),
.TRUE,
.fromBool(exclusive),
)) {
.SUCCESS => {
syscall.finish();
@@ -9382,8 +9380,8 @@ fn fileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!
&windows_lock_range_off,
&windows_lock_range_len,
null,
windows.TRUE,
windows.FALSE,
.TRUE,
.FALSE,
)) {
.SUCCESS => break syscall.finish(),
.CANCELLED => {
@@ -11469,7 +11467,7 @@ fn clockResolution(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.ResolutionEr
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
var qpf: windows.LARGE_INTEGER = undefined;
if (windows.ntdll.RtlQueryPerformanceFrequency(&qpf) != 0) {
if (windows.ntdll.RtlQueryPerformanceFrequency(&qpf).toBool()) {
recoverableOsBugDetected();
return .zero;
}
@@ -11523,14 +11521,14 @@ fn nowWindows(clock: Io.Clock) Io.Timestamp {
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
const qpf: u64 = qpf: {
var qpf: windows.LARGE_INTEGER = undefined;
assert(windows.ntdll.RtlQueryPerformanceFrequency(&qpf) != windows.FALSE);
assert(windows.ntdll.RtlQueryPerformanceFrequency(&qpf).toBool());
break :qpf @bitCast(qpf);
};
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
const qpc: u64 = qpc: {
var qpc: windows.LARGE_INTEGER = undefined;
assert(windows.ntdll.RtlQueryPerformanceCounter(&qpc) != windows.FALSE);
assert(windows.ntdll.RtlQueryPerformanceCounter(&qpc).toBool());
break :qpc @bitCast(qpc);
};
@@ -11745,9 +11743,9 @@ fn netListenIpWindows(
.file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } },
.code = windows.IOCTL.AFD.START_LISTEN,
.in = @ptrCast(&windows.AFD.LISTEN_INFO{
.UseSAN = windows.FALSE,
.UseSAN = .FALSE,
.MaximumConnectionQueue = options.kernel_backlog,
.UseDelayedAcceptance = windows.FALSE,
.UseDelayedAcceptance = .FALSE,
}),
})).u.Status) {
.SUCCESS => {},
@@ -11830,9 +11828,9 @@ fn netListenUnixWindows(
.file = .{ .handle = socket_handle, .flags = .{ .nonblocking = true } },
.code = windows.IOCTL.AFD.START_LISTEN,
.in = @ptrCast(&windows.AFD.LISTEN_INFO{
.UseSAN = windows.FALSE,
.UseSAN = .FALSE,
.MaximumConnectionQueue = options.kernel_backlog,
.UseDelayedAcceptance = windows.FALSE,
.UseDelayedAcceptance = .FALSE,
}),
})).u.Status) {
.SUCCESS => {},
@@ -12529,7 +12527,7 @@ fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle, opt
.file = .{ .handle = listen_handle, .flags = .{ .nonblocking = true } },
.code = windows.IOCTL.AFD.ACCEPT,
.in = @ptrCast(&windows.AFD.ACCEPT_INFO{
.UseSAN = windows.FALSE,
.UseSAN = .FALSE,
.Sequence = storage.Info.Sequence,
.AcceptHandle = accept_handle,
}),
@@ -12550,7 +12548,7 @@ fn deferAcceptAfd(t: *Threaded, listen_handle: net.Socket.Handle, info: windows.
.code = windows.IOCTL.AFD.DEFER_ACCEPT,
.in = @ptrCast(&windows.AFD.DEFER_ACCEPT_INFO{
.Sequence = info.Sequence,
.Reject = windows.FALSE,
.Reject = .FALSE,
}),
}) catch |err| switch (err) {
error.Canceled => unreachable, // blocked
@@ -15098,7 +15096,7 @@ fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT
switch (windows.ntdll.NtTerminateProcess(handle, @enumFromInt(exit_code))) {
.SUCCESS, .PROCESS_IS_TERMINATING => {
const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
_ = windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &infinite_timeout);
_ = windows.ntdll.NtWaitForSingleObject(handle, .FALSE, &infinite_timeout);
childCleanupWindows(child);
},
.ACCESS_DENIED => {
@@ -15108,7 +15106,7 @@ fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT
// PROCESS_TERMINATE access right, so let's do another check to make
// sure the process is really no longer running:
const minimal_timeout: windows.LARGE_INTEGER = -1;
return switch (windows.ntdll.NtWaitForSingleObject(handle, windows.FALSE, &minimal_timeout)) {
return switch (windows.ntdll.NtWaitForSingleObject(handle, .FALSE, &minimal_timeout)) {
windows.NTSTATUS.WAIT_0 => error.AlreadyTerminated,
else => error.AccessDenied,
};
@@ -15122,7 +15120,7 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child
const alertable_syscall: AlertableSyscall = try .start();
const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
while (true) switch (windows.ntdll.NtWaitForSingleObject(handle, windows.TRUE, &infinite_timeout)) {
while (true) switch (windows.ntdll.NtWaitForSingleObject(handle, .TRUE, &infinite_timeout)) {
windows.NTSTATUS.WAIT_0 => break alertable_syscall.finish(),
.USER_APC, .ALERTED, .TIMEOUT => {
try alertable_syscall.checkCancel();
@@ -15458,7 +15456,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro
.sa = &.{
.nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = null,
.bInheritHandle = windows.TRUE,
.bInheritHandle = .TRUE,
},
.creation = .OPEN,
}),
@@ -15477,7 +15475,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro
.sa = &.{
.nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = null,
.bInheritHandle = windows.TRUE,
.bInheritHandle = .TRUE,
},
.creation = .OPEN,
}),
@@ -15496,7 +15494,7 @@ fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) pro
.sa = &.{
.nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = null,
.bInheritHandle = windows.TRUE,
.bInheritHandle = .TRUE,
},
.creation = .OPEN,
}),
@@ -16021,9 +16019,9 @@ fn windowsCreateProcessPathExt(
&file_information_buf,
file_information_buf.len,
.Directory,
windows.FALSE, // single result
.FALSE, // single result
&.init(app_name_wildcard),
windows.FALSE, // restart iteration
.FALSE, // restart iteration
)) {
.SUCCESS => {},
.NO_SUCH_FILE => return error.FileNotFound,
@@ -16184,13 +16182,13 @@ fn windowsCreateProcess(
cmd_line,
null,
null,
windows.TRUE,
.TRUE,
flags,
if (env_block) |block| block.slice.ptr else null,
cwd_ptr,
lpStartupInfo,
lpProcessInformation,
) != 0) {
).toBool()) {
return syscall.finish();
} else switch (windows.GetLastError()) {
.INVALID_PARAMETER => unreachable,
@@ -18742,7 +18740,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
const attr: windows.OBJECT.ATTRIBUTES = .{
.RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else options.dir,
.Attributes = .{ .INHERIT = if (options.sa) |sa| sa.bInheritHandle != windows.FALSE else false },
.Attributes = .{ .INHERIT = if (options.sa) |sa| sa.bInheritHandle.toBool() else false },
.ObjectName = @constCast(&windows.UNICODE_STRING.init(sub_path_w)),
.SecurityDescriptor = if (options.sa) |ptr| ptr.lpSecurityDescriptor else null,
};
+1 -2
View File
@@ -285,8 +285,7 @@ test "memory mapping fallback" {
/// because it allocates.
fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !Io.Threaded.WindowsPathSpace {
var out: windows.UNICODE_STRING = undefined;
const rc = windows.ntdll.RtlDosPathNameToNtPathName_U(path, &out, null, null);
if (rc != windows.TRUE) return error.BadPathName;
if (!windows.ntdll.RtlDosPathNameToNtPathName_U(path, &out, null, null).toBool()) return error.BadPathName;
defer windows.ntdll.RtlFreeUnicodeString(&out);
var path_space: Io.Threaded.WindowsPathSpace = undefined;
+1 -1
View File
@@ -646,7 +646,7 @@ const WindowsThreadImpl = struct {
fn join(self: Impl) void {
const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
switch (windows.ntdll.NtWaitForSingleObject(self.thread.thread_handle, windows.FALSE, &infinite_timeout)) {
switch (windows.ntdll.NtWaitForSingleObject(self.thread.thread_handle, .FALSE, &infinite_timeout)) {
windows.NTSTATUS.WAIT_0 => {},
else => |status| windows.unexpectedStatus(status) catch unreachable,
}
+32 -13
View File
@@ -895,9 +895,9 @@ pub const CONSOLE = struct {
/// input
Mode: MODE,
pub const MODE = enum(BOOLEAN) {
Input = FALSE,
Output = TRUE,
pub const MODE = enum(BOOLEAN.Backing) {
Input,
Output,
};
};
@@ -907,9 +907,9 @@ pub const CONSOLE = struct {
/// input
Mode: MODE,
pub const MODE = enum(BOOLEAN) {
Character = FALSE,
WideCharacter = TRUE,
pub const MODE = enum(BOOLEAN.Backing) {
Character,
WideCharacter,
};
};
@@ -1930,7 +1930,7 @@ pub const DNS = struct {
pub const @"3" = extern struct {
Base: REQUEST,
IsNetworkQueryRequired: BOOL = FALSE,
IsNetworkQueryRequired: BOOL = .FALSE,
RequiredNetworkIndex: DWORD = 0,
cCustomServers: DWORD = 0,
pCustomServers: ?*CUSTOM_SERVER = null,
@@ -4018,7 +4018,7 @@ pub fn eqlIgnoreCaseWtf16(a: []const u16, b: []const u16) bool {
}
// Use RtlEqualUnicodeString on Windows when not in comptime to avoid including a
// redundant copy of the uppercase data.
return ntdll.RtlEqualUnicodeString(&.init(a), &.init(b), TRUE) == TRUE;
return ntdll.RtlEqualUnicodeString(&.init(a), &.init(b), .TRUE).toBool();
}
/// Compares two WTF-8 strings using the equivalent functionality of
@@ -4270,8 +4270,8 @@ pub const Win32Error = @import("windows/win32error.zig").Win32Error;
pub const LANG = @import("windows/lang.zig");
pub const SUBLANG = @import("windows/sublang.zig");
pub const BOOL = c_int;
pub const BOOLEAN = BYTE;
pub const BOOL = Bool(c_int);
pub const BOOLEAN = Bool(BYTE);
pub const BYTE = u8;
pub const CHAR = u8;
pub const UCHAR = u8;
@@ -4376,8 +4376,27 @@ fn STRING(comptime C: type) type {
pub const ANSI_STRING = STRING(CHAR);
pub const UNICODE_STRING = STRING(WCHAR);
pub const TRUE = 1;
pub const FALSE = 0;
fn Bool(comptime BackingInteger: type) type {
return enum(Backing) {
/// false
FALSE = 0,
/// true
_,
/// This is not the only truthy value, comparisons against this value are always a bug.
pub const TRUE: @This() = @enumFromInt(1);
pub const Backing = BackingInteger;
pub fn toBool(b: @This()) bool {
return b != .FALSE;
}
pub fn fromBool(b: bool) @This() {
return @enumFromInt(@intFromBool(b));
}
};
}
pub const INVALID_HANDLE_VALUE: HANDLE = @ptrFromInt(maxInt(usize));
@@ -6087,7 +6106,7 @@ pub const SharedUserData: *const KUSER_SHARED_DATA = @ptrFromInt(0x7FFE0000);
pub fn IsProcessorFeaturePresent(feature: PF) bool {
if (@intFromEnum(feature) >= PROCESSOR_FEATURE_MAX) return false;
return SharedUserData.ProcessorFeatures[@intFromEnum(feature)] == 1;
return SharedUserData.ProcessorFeatures[@intFromEnum(feature)].toBool();
}
// https://github.com/reactos/reactos/blob/master/sdk/include/ndk/pstypes.h#L977-L983
+1 -1
View File
@@ -800,7 +800,7 @@ pub fn abort() noreturn {
// even when linking libc on Windows we use our own abort implementation.
// See https://github.com/ziglang/zig/issues/2071 for more details.
if (native_os == .windows) {
if (builtin.mode == .Debug and windows.peb().BeingDebugged != 0) {
if (builtin.mode == .Debug and windows.peb().BeingDebugged.toBool()) {
@breakpoint();
}
windows.ntdll.RtlExitUserProcess(3);
+1 -1
View File
@@ -84,7 +84,7 @@ fn _DllMainCRTStartup(
return root.DllMain(hinstDLL, fdwReason, lpReserved);
}
return std.os.windows.TRUE;
return .TRUE;
}
fn wasm_freestanding_start() callconv(.c) void {
+4 -6
View File
@@ -129,20 +129,18 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
};
var proc_info: windows.PROCESS.INFORMATION = undefined;
if (windows.kernel32.CreateProcessW(
if (!windows.kernel32.CreateProcessW(
@constCast(verify_path.ptr),
@constCast(cmd_line.ptr),
null,
null,
windows.TRUE,
.TRUE,
.{},
null,
null,
&startup_info,
&proc_info,
) == 0) {
std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.GetLastError()});
}
).toBool()) std.process.fatal("kernel32 CreateProcessW failed with {t}", .{windows.GetLastError()});
windows.CloseHandle(proc_info.hThread);
@@ -150,7 +148,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO
};
defer windows.CloseHandle(child_proc);
const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER);
switch (windows.ntdll.NtWaitForSingleObject(child_proc, windows.FALSE, &infinite_timeout)) {
switch (windows.ntdll.NtWaitForSingleObject(child_proc, .FALSE, &infinite_timeout)) {
windows.NTSTATUS.WAIT_0 => {},
.TIMEOUT => return error.WaitTimeOut,
else => |status| return windows.unexpectedStatus(status),
+8 -29
View File
@@ -29,16 +29,10 @@ pub fn main(init: std.process.Init) !void {
defer gpa.free(tmp_relative_path);
// Clear PATH
std.debug.assert(SetEnvironmentVariableW(
utf16Literal("PATH"),
null,
) == windows.TRUE);
std.debug.assert(SetEnvironmentVariableW(utf16Literal("PATH"), null).toBool());
// Set PATHEXT to something predictable
std.debug.assert(SetEnvironmentVariableW(
utf16Literal("PATHEXT"),
utf16Literal(".COM;.EXE;.BAT;.CMD;.JS"),
) == windows.TRUE);
std.debug.assert(SetEnvironmentVariableW(utf16Literal("PATHEXT"), utf16Literal(".COM;.EXE;.BAT;.CMD;.JS")).toBool());
// No PATH, so it should fail to find anything not in the cwd
try testExecError(error.FileNotFound, gpa, io, "something_missing");
@@ -46,10 +40,7 @@ pub fn main(init: std.process.Init) !void {
// make sure we don't get error.BadPath traversing out of cwd with a relative path
try testExecError(error.FileNotFound, gpa, io, "..\\.\\.\\.\\\\..\\more_missing");
std.debug.assert(SetEnvironmentVariableW(
utf16Literal("PATH"),
tmp_absolute_path_w,
) == windows.TRUE);
std.debug.assert(SetEnvironmentVariableW(utf16Literal("PATH"), tmp_absolute_path_w).toBool());
// Move hello.exe into the tmp dir which is now added to the path
try Io.Dir.cwd().copyFile(hello_exe_cache_path, tmp_dir, "hello.exe", io, .{});
@@ -129,10 +120,7 @@ pub fn main(init: std.process.Init) !void {
const something_subdir_abs_path = try std.mem.concatWithSentinel(gpa, u16, &.{ tmp_absolute_path_w, utf16Literal("\\something") }, 0);
defer gpa.free(something_subdir_abs_path);
std.debug.assert(SetEnvironmentVariableW(
utf16Literal("PATH"),
something_subdir_abs_path,
) == windows.TRUE);
std.debug.assert(SetEnvironmentVariableW(utf16Literal("PATH"), something_subdir_abs_path).toBool());
// Now trying to execute goodbye should give error.InvalidExe since it's the original
// error that we got when trying within the cwd
@@ -169,18 +157,12 @@ pub fn main(init: std.process.Init) !void {
defer gpa.free(denormed_something_subdir_wtf8);
// clear the path to ensure that the match comes from the cwd
std.debug.assert(SetEnvironmentVariableW(
utf16Literal("PATH"),
null,
) == windows.TRUE);
std.debug.assert(SetEnvironmentVariableW(utf16Literal("PATH"), null).toBool());
try testExecWithCwd(gpa, io, "goodbye", denormed_something_subdir_wtf8, "hello from exe\n");
// normalization should also work if the non-normalized path is found in the PATH var.
std.debug.assert(SetEnvironmentVariableW(
utf16Literal("PATH"),
denormed_something_subdir_abs_path,
) == windows.TRUE);
std.debug.assert(SetEnvironmentVariableW(utf16Literal("PATH"), denormed_something_subdir_abs_path).toBool());
try testExec(gpa, io, "goodbye", "hello from exe\n");
// now make sure we can launch executables "outside" of the cwd
@@ -191,10 +173,7 @@ pub fn main(init: std.process.Init) !void {
try std.process.setCurrentDir(io, subdir_cwd);
// clear the PATH again
std.debug.assert(SetEnvironmentVariableW(
utf16Literal("PATH"),
null,
) == windows.TRUE);
std.debug.assert(SetEnvironmentVariableW(utf16Literal("PATH"), null).toBool());
// while we're at it make sure non-windows separators work fine
try testExec(gpa, io, "../hello", "hello from exe\n");
@@ -237,7 +216,7 @@ fn renameExe(dir: Io.Dir, io: Io, old_sub_path: []const u8, new_sub_path: []cons
if (attempt == 26) return error.AccessDenied;
// give the kernel a chance to finish closing the executable handle
const interval = @as(std.os.windows.LARGE_INTEGER, -1) << attempt;
_ = std.os.windows.ntdll.NtDelayExecution(std.os.windows.FALSE, &interval);
_ = std.os.windows.ntdll.NtDelayExecution(.FALSE, &interval);
attempt += 1;
continue;
},