mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge remote-tracking branch 'origin/master' into llvm13
Conflicts: lib/libcxx/include/__config d57c0cc3bfeff9af297279759ec2b631e6d95140 added support for DragonFlyBSD to libc++ by updating some ifdefs. This needed to be synced with llvm13.
This commit is contained in:
commit
6aeab0f323
@ -426,7 +426,7 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
"${CMAKE_SOURCE_DIR}/lib/std/os.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/bits.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/bits.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/errno-generic.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/errno/generic.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/netlink.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/netlink.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/prctl.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/prctl.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/securebits.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/bits/linux/securebits.zig"
|
||||||
|
|||||||
68
build.zig
68
build.zig
@ -17,8 +17,10 @@ pub fn build(b: *Builder) !void {
|
|||||||
b.setPreferredReleaseMode(.ReleaseFast);
|
b.setPreferredReleaseMode(.ReleaseFast);
|
||||||
const mode = b.standardReleaseOptions();
|
const mode = b.standardReleaseOptions();
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode") orelse false;
|
||||||
|
|
||||||
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
||||||
|
docgen_exe.single_threaded = single_threaded;
|
||||||
|
|
||||||
const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
|
const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
|
||||||
const langref_out_path = fs.path.join(
|
const langref_out_path = fs.path.join(
|
||||||
@ -41,6 +43,7 @@ pub fn build(b: *Builder) !void {
|
|||||||
var test_stage2 = b.addTest("src/test.zig");
|
var test_stage2 = b.addTest("src/test.zig");
|
||||||
test_stage2.setBuildMode(mode);
|
test_stage2.setBuildMode(mode);
|
||||||
test_stage2.addPackagePath("test_cases", "test/cases.zig");
|
test_stage2.addPackagePath("test_cases", "test/cases.zig");
|
||||||
|
test_stage2.single_threaded = single_threaded;
|
||||||
|
|
||||||
const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
|
const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
|
||||||
|
|
||||||
@ -104,10 +107,15 @@ pub fn build(b: *Builder) !void {
|
|||||||
exe.setTarget(target);
|
exe.setTarget(target);
|
||||||
toolchain_step.dependOn(&exe.step);
|
toolchain_step.dependOn(&exe.step);
|
||||||
b.default_step.dependOn(&exe.step);
|
b.default_step.dependOn(&exe.step);
|
||||||
|
exe.single_threaded = single_threaded;
|
||||||
|
|
||||||
|
const exe_options = b.addOptions();
|
||||||
|
exe.addOptions("build_options", exe_options);
|
||||||
|
|
||||||
|
exe_options.addOption(u32, "mem_leak_frames", mem_leak_frames);
|
||||||
|
exe_options.addOption(bool, "skip_non_native", skip_non_native);
|
||||||
|
exe_options.addOption(bool, "have_llvm", enable_llvm);
|
||||||
|
|
||||||
exe.addBuildOption(u32, "mem_leak_frames", mem_leak_frames);
|
|
||||||
exe.addBuildOption(bool, "skip_non_native", skip_non_native);
|
|
||||||
exe.addBuildOption(bool, "have_llvm", enable_llvm);
|
|
||||||
if (enable_llvm) {
|
if (enable_llvm) {
|
||||||
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
|
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
|
||||||
|
|
||||||
@ -131,6 +139,7 @@ pub fn build(b: *Builder) !void {
|
|||||||
softfloat.addIncludeDir("deps/SoftFloat-3e/source/8086");
|
softfloat.addIncludeDir("deps/SoftFloat-3e/source/8086");
|
||||||
softfloat.addIncludeDir("deps/SoftFloat-3e/source/include");
|
softfloat.addIncludeDir("deps/SoftFloat-3e/source/include");
|
||||||
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
|
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
|
||||||
|
softfloat.single_threaded = single_threaded;
|
||||||
|
|
||||||
exe.linkLibrary(softfloat);
|
exe.linkLibrary(softfloat);
|
||||||
test_stage2.linkLibrary(softfloat);
|
test_stage2.linkLibrary(softfloat);
|
||||||
@ -213,15 +222,15 @@ pub fn build(b: *Builder) !void {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
exe.addBuildOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
|
exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
|
||||||
|
|
||||||
const semver = try std.SemanticVersion.parse(version);
|
const semver = try std.SemanticVersion.parse(version);
|
||||||
exe.addBuildOption(std.SemanticVersion, "semver", semver);
|
exe_options.addOption(std.SemanticVersion, "semver", semver);
|
||||||
|
|
||||||
exe.addBuildOption(bool, "enable_logging", enable_logging);
|
exe_options.addOption(bool, "enable_logging", enable_logging);
|
||||||
exe.addBuildOption(bool, "enable_tracy", tracy != null);
|
exe_options.addOption(bool, "enable_tracy", tracy != null);
|
||||||
exe.addBuildOption(bool, "is_stage1", is_stage1);
|
exe_options.addOption(bool, "is_stage1", is_stage1);
|
||||||
exe.addBuildOption(bool, "omit_stage2", omit_stage2);
|
exe_options.addOption(bool, "omit_stage2", omit_stage2);
|
||||||
if (tracy) |tracy_path| {
|
if (tracy) |tracy_path| {
|
||||||
const client_cpp = fs.path.join(
|
const client_cpp = fs.path.join(
|
||||||
b.allocator,
|
b.allocator,
|
||||||
@ -243,20 +252,23 @@ pub fn build(b: *Builder) !void {
|
|||||||
const is_darling_enabled = b.option(bool, "enable-darling", "[Experimental] Use Darling to run cross compiled macOS tests") orelse false;
|
const is_darling_enabled = b.option(bool, "enable-darling", "[Experimental] Use Darling to run cross compiled macOS tests") orelse false;
|
||||||
const glibc_multi_dir = b.option([]const u8, "enable-foreign-glibc", "Provide directory with glibc installations to run cross compiled tests that link glibc");
|
const glibc_multi_dir = b.option([]const u8, "enable-foreign-glibc", "Provide directory with glibc installations to run cross compiled tests that link glibc");
|
||||||
|
|
||||||
test_stage2.addBuildOption(bool, "enable_logging", enable_logging);
|
const test_stage2_options = b.addOptions();
|
||||||
test_stage2.addBuildOption(bool, "skip_non_native", skip_non_native);
|
test_stage2.addOptions("build_options", test_stage2_options);
|
||||||
test_stage2.addBuildOption(bool, "skip_compile_errors", skip_compile_errors);
|
|
||||||
test_stage2.addBuildOption(bool, "is_stage1", is_stage1);
|
test_stage2_options.addOption(bool, "enable_logging", enable_logging);
|
||||||
test_stage2.addBuildOption(bool, "omit_stage2", omit_stage2);
|
test_stage2_options.addOption(bool, "skip_non_native", skip_non_native);
|
||||||
test_stage2.addBuildOption(bool, "have_llvm", enable_llvm);
|
test_stage2_options.addOption(bool, "skip_compile_errors", skip_compile_errors);
|
||||||
test_stage2.addBuildOption(bool, "enable_qemu", is_qemu_enabled);
|
test_stage2_options.addOption(bool, "is_stage1", is_stage1);
|
||||||
test_stage2.addBuildOption(bool, "enable_wine", is_wine_enabled);
|
test_stage2_options.addOption(bool, "omit_stage2", omit_stage2);
|
||||||
test_stage2.addBuildOption(bool, "enable_wasmtime", is_wasmtime_enabled);
|
test_stage2_options.addOption(bool, "have_llvm", enable_llvm);
|
||||||
test_stage2.addBuildOption(u32, "mem_leak_frames", mem_leak_frames * 2);
|
test_stage2_options.addOption(bool, "enable_qemu", is_qemu_enabled);
|
||||||
test_stage2.addBuildOption(bool, "enable_darling", is_darling_enabled);
|
test_stage2_options.addOption(bool, "enable_wine", is_wine_enabled);
|
||||||
test_stage2.addBuildOption(?[]const u8, "glibc_multi_install_dir", glibc_multi_dir);
|
test_stage2_options.addOption(bool, "enable_wasmtime", is_wasmtime_enabled);
|
||||||
test_stage2.addBuildOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
|
test_stage2_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2);
|
||||||
test_stage2.addBuildOption(std.SemanticVersion, "semver", semver);
|
test_stage2_options.addOption(bool, "enable_darling", is_darling_enabled);
|
||||||
|
test_stage2_options.addOption(?[]const u8, "glibc_multi_install_dir", glibc_multi_dir);
|
||||||
|
test_stage2_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
|
||||||
|
test_stage2_options.addOption(std.SemanticVersion, "semver", semver);
|
||||||
|
|
||||||
const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
|
const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
|
||||||
test_stage2_step.dependOn(&test_stage2.step);
|
test_stage2_step.dependOn(&test_stage2.step);
|
||||||
@ -296,7 +308,7 @@ pub fn build(b: *Builder) !void {
|
|||||||
"behavior",
|
"behavior",
|
||||||
"Run the behavior tests",
|
"Run the behavior tests",
|
||||||
modes,
|
modes,
|
||||||
false,
|
false, // skip_single_threaded
|
||||||
skip_non_native,
|
skip_non_native,
|
||||||
skip_libc,
|
skip_libc,
|
||||||
is_wine_enabled,
|
is_wine_enabled,
|
||||||
@ -313,9 +325,9 @@ pub fn build(b: *Builder) !void {
|
|||||||
"compiler-rt",
|
"compiler-rt",
|
||||||
"Run the compiler_rt tests",
|
"Run the compiler_rt tests",
|
||||||
modes,
|
modes,
|
||||||
true,
|
true, // skip_single_threaded
|
||||||
skip_non_native,
|
skip_non_native,
|
||||||
true,
|
true, // skip_libc
|
||||||
is_wine_enabled,
|
is_wine_enabled,
|
||||||
is_qemu_enabled,
|
is_qemu_enabled,
|
||||||
is_wasmtime_enabled,
|
is_wasmtime_enabled,
|
||||||
@ -330,9 +342,9 @@ pub fn build(b: *Builder) !void {
|
|||||||
"minilibc",
|
"minilibc",
|
||||||
"Run the mini libc tests",
|
"Run the mini libc tests",
|
||||||
modes,
|
modes,
|
||||||
true,
|
true, // skip_single_threaded
|
||||||
skip_non_native,
|
skip_non_native,
|
||||||
true,
|
true, // skip_libc
|
||||||
is_wine_enabled,
|
is_wine_enabled,
|
||||||
is_qemu_enabled,
|
is_qemu_enabled,
|
||||||
is_wasmtime_enabled,
|
is_wasmtime_enabled,
|
||||||
|
|||||||
@ -887,16 +887,6 @@ fn tokenizeAndPrintRaw(
|
|||||||
next_tok_is_fn = true;
|
next_tok_is_fn = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_undefined,
|
|
||||||
.keyword_null,
|
|
||||||
.keyword_true,
|
|
||||||
.keyword_false,
|
|
||||||
=> {
|
|
||||||
try out.writeAll("<span class=\"tok-null\">");
|
|
||||||
try writeEscaped(out, src[token.loc.start..token.loc.end]);
|
|
||||||
try out.writeAll("</span>");
|
|
||||||
},
|
|
||||||
|
|
||||||
.string_literal,
|
.string_literal,
|
||||||
.multiline_string_literal_line,
|
.multiline_string_literal_line,
|
||||||
.char_literal,
|
.char_literal,
|
||||||
@ -921,9 +911,18 @@ fn tokenizeAndPrintRaw(
|
|||||||
},
|
},
|
||||||
|
|
||||||
.identifier => {
|
.identifier => {
|
||||||
if (prev_tok_was_fn) {
|
const tok_bytes = src[token.loc.start..token.loc.end];
|
||||||
|
if (mem.eql(u8, tok_bytes, "undefined") or
|
||||||
|
mem.eql(u8, tok_bytes, "null") or
|
||||||
|
mem.eql(u8, tok_bytes, "true") or
|
||||||
|
mem.eql(u8, tok_bytes, "false"))
|
||||||
|
{
|
||||||
|
try out.writeAll("<span class=\"tok-null\">");
|
||||||
|
try writeEscaped(out, tok_bytes);
|
||||||
|
try out.writeAll("</span>");
|
||||||
|
} else if (prev_tok_was_fn) {
|
||||||
try out.writeAll("<span class=\"tok-fn\">");
|
try out.writeAll("<span class=\"tok-fn\">");
|
||||||
try writeEscaped(out, src[token.loc.start..token.loc.end]);
|
try writeEscaped(out, tok_bytes);
|
||||||
try out.writeAll("</span>");
|
try out.writeAll("</span>");
|
||||||
} else {
|
} else {
|
||||||
const is_int = blk: {
|
const is_int = blk: {
|
||||||
@ -938,12 +937,12 @@ fn tokenizeAndPrintRaw(
|
|||||||
}
|
}
|
||||||
break :blk true;
|
break :blk true;
|
||||||
};
|
};
|
||||||
if (is_int or isType(src[token.loc.start..token.loc.end])) {
|
if (is_int or isType(tok_bytes)) {
|
||||||
try out.writeAll("<span class=\"tok-type\">");
|
try out.writeAll("<span class=\"tok-type\">");
|
||||||
try writeEscaped(out, src[token.loc.start..token.loc.end]);
|
try writeEscaped(out, tok_bytes);
|
||||||
try out.writeAll("</span>");
|
try out.writeAll("</span>");
|
||||||
} else {
|
} else {
|
||||||
try writeEscaped(out, src[token.loc.start..token.loc.end]);
|
try writeEscaped(out, tok_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -38,15 +38,20 @@
|
|||||||
.file {
|
.file {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
pre,code {
|
|
||||||
font-size: 12pt;
|
|
||||||
}
|
|
||||||
pre > code {
|
pre > code {
|
||||||
display: block;
|
display: block;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
color: #333;
|
color: #333;
|
||||||
background: #f8f8f8;
|
background: #f8f8f8;
|
||||||
|
border: 1px dotted silver;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border: 1px dotted silver;
|
||||||
|
padding-left: 0.3em;
|
||||||
|
padding-right: 0.3em;
|
||||||
}
|
}
|
||||||
.table-wrapper {
|
.table-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -95,6 +100,7 @@
|
|||||||
#contents {
|
#contents {
|
||||||
max-width: 60em;
|
max-width: 60em;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toc {
|
#toc {
|
||||||
@ -153,6 +159,11 @@
|
|||||||
pre > code {
|
pre > code {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
background: #222;
|
background: #222;
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
background-color: #222;
|
||||||
|
border-color: #444;
|
||||||
}
|
}
|
||||||
.tok-kw {
|
.tok-kw {
|
||||||
color: #eee;
|
color: #eee;
|
||||||
@ -3152,7 +3163,9 @@ test "switch using enum literals" {
|
|||||||
It must specify a tag type and cannot consume every enumeration value.
|
It must specify a tag type and cannot consume every enumeration value.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{#link|@intToEnum#} on a non-exhaustive enum cannot fail.
|
{#link|@intToEnum#} on a non-exhaustive enum involves the safety semantics
|
||||||
|
of {#link|@intCast#} to the integer tag type, but beyond that always results in
|
||||||
|
a well-defined enum value.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong
|
A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong
|
||||||
@ -6634,14 +6647,21 @@ test "global assembly" {
|
|||||||
<p>
|
<p>
|
||||||
When a function is called, a frame is pushed to the stack,
|
When a function is called, a frame is pushed to the stack,
|
||||||
the function runs until it reaches a return statement, and then the frame is popped from the stack.
|
the function runs until it reaches a return statement, and then the frame is popped from the stack.
|
||||||
At the callsite, the following code does not run until the function returns.
|
The code following the callsite does not run until the function returns.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation,
|
An async function is a function whose execution is split into an {#syntax#}async{#endsyntax#} initiation,
|
||||||
followed by an {#syntax#}await{#endsyntax#} completion. Its frame is
|
followed by an {#syntax#}await{#endsyntax#} completion. Its frame is
|
||||||
provided explicitly by the caller, and it can be suspended and resumed any number of times.
|
provided explicitly by the caller, and it can be suspended and resumed any number of times.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
The code following the {#syntax#}async{#endsyntax#} callsite runs immediately after the async
|
||||||
|
function first suspends. When the return value of the async function is needed,
|
||||||
|
the calling code can {#syntax#}await{#endsyntax#} on the async function frame.
|
||||||
|
This will suspend the calling code until the async function completes, at which point
|
||||||
|
execution resumes just after the {#syntax#}await{#endsyntax#} callsite.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
Zig infers that a function is {#syntax#}async{#endsyntax#} when it observes that the function contains
|
Zig infers that a function is {#syntax#}async{#endsyntax#} when it observes that the function contains
|
||||||
a <strong>suspension point</strong>. Async functions can be called the same as normal functions. A
|
a <strong>suspension point</strong>. Async functions can be called the same as normal functions. A
|
||||||
function call of an async function is a suspend point.
|
function call of an async function is a suspend point.
|
||||||
@ -6744,7 +6764,14 @@ fn testResumeFromSuspend(my_result: *i32) void {
|
|||||||
{#header_open|Async and Await#}
|
{#header_open|Async and Await#}
|
||||||
<p>
|
<p>
|
||||||
In the same way that every {#syntax#}suspend{#endsyntax#} has a matching
|
In the same way that every {#syntax#}suspend{#endsyntax#} has a matching
|
||||||
{#syntax#}resume{#endsyntax#}, every {#syntax#}async{#endsyntax#} has a matching {#syntax#}await{#endsyntax#}.
|
{#syntax#}resume{#endsyntax#}, every {#syntax#}async{#endsyntax#} has a matching {#syntax#}await{#endsyntax#}
|
||||||
|
in standard code.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
However, it is possible to have an {#syntax#}async{#endsyntax#} call
|
||||||
|
without a matching {#syntax#}await{#endsyntax#}. Upon completion of the async function,
|
||||||
|
execution would continue at the most recent {#syntax#}async{#endsyntax#} callsite or {#syntax#}resume{#endsyntax#} callsite,
|
||||||
|
and the return value of the async function would be lost.
|
||||||
</p>
|
</p>
|
||||||
{#code_begin|test#}
|
{#code_begin|test#}
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
@ -6779,7 +6806,9 @@ fn func() void {
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{#syntax#}await{#endsyntax#} is a suspend point, and takes as an operand anything that
|
{#syntax#}await{#endsyntax#} is a suspend point, and takes as an operand anything that
|
||||||
coerces to {#syntax#}anyframe->T{#endsyntax#}.
|
coerces to {#syntax#}anyframe->T{#endsyntax#}. Calling {#syntax#}await{#endsyntax#} on
|
||||||
|
the frame of an async function will cause execution to continue at the
|
||||||
|
{#syntax#}await{#endsyntax#} callsite once the target function completes.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
There is a common misconception that {#syntax#}await{#endsyntax#} resumes the target function.
|
There is a common misconception that {#syntax#}await{#endsyntax#} resumes the target function.
|
||||||
@ -7945,7 +7974,7 @@ test "@hasDecl" {
|
|||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@intToEnum#}
|
{#header_open|@intToEnum#}
|
||||||
<pre>{#syntax#}@intToEnum(comptime DestType: type, int_value: std.meta.Tag(DestType)) DestType{#endsyntax#}</pre>
|
<pre>{#syntax#}@intToEnum(comptime DestType: type, integer: anytype) DestType{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts an integer into an {#link|enum#} value.
|
Converts an integer into an {#link|enum#} value.
|
||||||
</p>
|
</p>
|
||||||
@ -11535,11 +11564,7 @@ PrimaryTypeExpr
|
|||||||
/ INTEGER
|
/ INTEGER
|
||||||
/ KEYWORD_comptime TypeExpr
|
/ KEYWORD_comptime TypeExpr
|
||||||
/ KEYWORD_error DOT IDENTIFIER
|
/ KEYWORD_error DOT IDENTIFIER
|
||||||
/ KEYWORD_false
|
|
||||||
/ KEYWORD_null
|
|
||||||
/ KEYWORD_anyframe
|
/ KEYWORD_anyframe
|
||||||
/ KEYWORD_true
|
|
||||||
/ KEYWORD_undefined
|
|
||||||
/ KEYWORD_unreachable
|
/ KEYWORD_unreachable
|
||||||
/ STRINGLITERAL
|
/ STRINGLITERAL
|
||||||
/ SwitchExpr
|
/ SwitchExpr
|
||||||
@ -11908,7 +11933,6 @@ KEYWORD_errdefer <- 'errdefer' end_of_word
|
|||||||
KEYWORD_error <- 'error' end_of_word
|
KEYWORD_error <- 'error' end_of_word
|
||||||
KEYWORD_export <- 'export' end_of_word
|
KEYWORD_export <- 'export' end_of_word
|
||||||
KEYWORD_extern <- 'extern' end_of_word
|
KEYWORD_extern <- 'extern' end_of_word
|
||||||
KEYWORD_false <- 'false' end_of_word
|
|
||||||
KEYWORD_fn <- 'fn' end_of_word
|
KEYWORD_fn <- 'fn' end_of_word
|
||||||
KEYWORD_for <- 'for' end_of_word
|
KEYWORD_for <- 'for' end_of_word
|
||||||
KEYWORD_if <- 'if' end_of_word
|
KEYWORD_if <- 'if' end_of_word
|
||||||
@ -11916,7 +11940,6 @@ KEYWORD_inline <- 'inline' end_of_word
|
|||||||
KEYWORD_noalias <- 'noalias' end_of_word
|
KEYWORD_noalias <- 'noalias' end_of_word
|
||||||
KEYWORD_nosuspend <- 'nosuspend' end_of_word
|
KEYWORD_nosuspend <- 'nosuspend' end_of_word
|
||||||
KEYWORD_noinline <- 'noinline' end_of_word
|
KEYWORD_noinline <- 'noinline' end_of_word
|
||||||
KEYWORD_null <- 'null' end_of_word
|
|
||||||
KEYWORD_opaque <- 'opaque' end_of_word
|
KEYWORD_opaque <- 'opaque' end_of_word
|
||||||
KEYWORD_or <- 'or' end_of_word
|
KEYWORD_or <- 'or' end_of_word
|
||||||
KEYWORD_orelse <- 'orelse' end_of_word
|
KEYWORD_orelse <- 'orelse' end_of_word
|
||||||
@ -11930,9 +11953,7 @@ KEYWORD_suspend <- 'suspend' end_of_word
|
|||||||
KEYWORD_switch <- 'switch' end_of_word
|
KEYWORD_switch <- 'switch' end_of_word
|
||||||
KEYWORD_test <- 'test' end_of_word
|
KEYWORD_test <- 'test' end_of_word
|
||||||
KEYWORD_threadlocal <- 'threadlocal' end_of_word
|
KEYWORD_threadlocal <- 'threadlocal' end_of_word
|
||||||
KEYWORD_true <- 'true' end_of_word
|
|
||||||
KEYWORD_try <- 'try' end_of_word
|
KEYWORD_try <- 'try' end_of_word
|
||||||
KEYWORD_undefined <- 'undefined' end_of_word
|
|
||||||
KEYWORD_union <- 'union' end_of_word
|
KEYWORD_union <- 'union' end_of_word
|
||||||
KEYWORD_unreachable <- 'unreachable' end_of_word
|
KEYWORD_unreachable <- 'unreachable' end_of_word
|
||||||
KEYWORD_usingnamespace <- 'usingnamespace' end_of_word
|
KEYWORD_usingnamespace <- 'usingnamespace' end_of_word
|
||||||
@ -11945,13 +11966,13 @@ keyword <- KEYWORD_align / KEYWORD_allowzero / KEYWORD_and / KEYWORD_anyframe
|
|||||||
/ KEYWORD_break / KEYWORD_callconv / KEYWORD_catch / KEYWORD_comptime
|
/ KEYWORD_break / KEYWORD_callconv / KEYWORD_catch / KEYWORD_comptime
|
||||||
/ KEYWORD_const / KEYWORD_continue / KEYWORD_defer / KEYWORD_else
|
/ KEYWORD_const / KEYWORD_continue / KEYWORD_defer / KEYWORD_else
|
||||||
/ KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export
|
/ KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export
|
||||||
/ KEYWORD_extern / KEYWORD_false / KEYWORD_fn / KEYWORD_for / KEYWORD_if
|
/ KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if
|
||||||
/ KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline
|
/ KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline
|
||||||
/ KEYWORD_null / KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed
|
/ KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed
|
||||||
/ KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
|
/ KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
|
||||||
/ KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch
|
/ KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch
|
||||||
/ KEYWORD_test / KEYWORD_threadlocal / KEYWORD_true / KEYWORD_try
|
/ KEYWORD_test / KEYWORD_threadlocal / KEYWORD_try
|
||||||
/ KEYWORD_undefined / KEYWORD_union / KEYWORD_unreachable
|
/ KEYWORD_union / KEYWORD_unreachable
|
||||||
/ KEYWORD_usingnamespace / KEYWORD_var / KEYWORD_volatile / KEYWORD_while
|
/ KEYWORD_usingnamespace / KEYWORD_var / KEYWORD_volatile / KEYWORD_while
|
||||||
</code></pre>
|
</code></pre>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|||||||
12
lib/libc/mingw/lib-common/compstui.def
vendored
Normal file
12
lib/libc/mingw/lib-common/compstui.def
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
;
|
||||||
|
; Exports of file COMPSTUI.dll
|
||||||
|
;
|
||||||
|
; Autogenerated by gen_exportdef
|
||||||
|
; Written by Kai Tietz, 2007
|
||||||
|
;
|
||||||
|
LIBRARY COMPSTUI.dll
|
||||||
|
EXPORTS
|
||||||
|
CommonPropertySheetUIA
|
||||||
|
CommonPropertySheetUIW
|
||||||
|
GetCPSUIUserData
|
||||||
|
SetCPSUIUserData
|
||||||
13
lib/libcxx/include/__config
vendored
13
lib/libcxx/include/__config
vendored
@ -125,7 +125,7 @@
|
|||||||
# endif
|
# endif
|
||||||
// Feature macros for disabling pre ABI v1 features. All of these options
|
// Feature macros for disabling pre ABI v1 features. All of these options
|
||||||
// are deprecated.
|
// are deprecated.
|
||||||
# if defined(__FreeBSD__)
|
# if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
# define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR
|
# define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -380,7 +380,7 @@
|
|||||||
# if __ANDROID_API__ >= 29
|
# if __ANDROID_API__ >= 29
|
||||||
# define _LIBCPP_HAS_TIMESPEC_GET
|
# define _LIBCPP_HAS_TIMESPEC_GET
|
||||||
# endif
|
# endif
|
||||||
# elif defined(__Fuchsia__) || defined(__wasi__) || defined(__NetBSD__)
|
# elif defined(__Fuchsia__) || defined(__wasi__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||||
# define _LIBCPP_HAS_ALIGNED_ALLOC
|
# define _LIBCPP_HAS_ALIGNED_ALLOC
|
||||||
# define _LIBCPP_HAS_QUICK_EXIT
|
# define _LIBCPP_HAS_QUICK_EXIT
|
||||||
# define _LIBCPP_HAS_TIMESPEC_GET
|
# define _LIBCPP_HAS_TIMESPEC_GET
|
||||||
@ -938,11 +938,11 @@ typedef unsigned int char32_t;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || \
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || \
|
||||||
defined(__sun__) || defined(__NetBSD__) || defined(__CloudABI__)
|
defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CloudABI__)
|
||||||
#define _LIBCPP_LOCALE__L_EXTENSIONS 1
|
#define _LIBCPP_LOCALE__L_EXTENSIONS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
#define _DECLARE_C99_LDBL_MATH 1
|
#define _DECLARE_C99_LDBL_MATH 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -970,11 +970,11 @@ typedef unsigned int char32_t;
|
|||||||
# define _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
|
# define _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
#define _LIBCPP_HAS_DEFAULTRUNELOCALE
|
#define _LIBCPP_HAS_DEFAULTRUNELOCALE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__)
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__sun__)
|
||||||
#define _LIBCPP_WCTYPE_IS_MASK
|
#define _LIBCPP_WCTYPE_IS_MASK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1138,6 +1138,7 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
|
|||||||
defined(__wasi__) || \
|
defined(__wasi__) || \
|
||||||
defined(__NetBSD__) || \
|
defined(__NetBSD__) || \
|
||||||
defined(__OpenBSD__) || \
|
defined(__OpenBSD__) || \
|
||||||
|
defined(__DragonFly__) || \
|
||||||
defined(__NuttX__) || \
|
defined(__NuttX__) || \
|
||||||
defined(__linux__) || \
|
defined(__linux__) || \
|
||||||
defined(__GNU__) || \
|
defined(__GNU__) || \
|
||||||
|
|||||||
6
lib/libcxx/include/__locale
vendored
6
lib/libcxx/include/__locale
vendored
@ -35,7 +35,7 @@
|
|||||||
# include <__support/newlib/xlocale.h>
|
# include <__support/newlib/xlocale.h>
|
||||||
#elif defined(__OpenBSD__)
|
#elif defined(__OpenBSD__)
|
||||||
# include <__support/openbsd/xlocale.h>
|
# include <__support/openbsd/xlocale.h>
|
||||||
#elif (defined(__APPLE__) || defined(__FreeBSD__) \
|
#elif (defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) \
|
||||||
|| defined(__EMSCRIPTEN__) || defined(__IBMCPP__))
|
|| defined(__EMSCRIPTEN__) || defined(__IBMCPP__))
|
||||||
# include <xlocale.h>
|
# include <xlocale.h>
|
||||||
#elif defined(__Fuchsia__)
|
#elif defined(__Fuchsia__)
|
||||||
@ -450,10 +450,10 @@ public:
|
|||||||
static const mask blank = _BLANK;
|
static const mask blank = _BLANK;
|
||||||
static const mask __regex_word = 0x80;
|
static const mask __regex_word = 0x80;
|
||||||
# define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
|
# define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
|
||||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__)
|
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||||
# ifdef __APPLE__
|
# ifdef __APPLE__
|
||||||
typedef __uint32_t mask;
|
typedef __uint32_t mask;
|
||||||
# elif defined(__FreeBSD__)
|
# elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
typedef unsigned long mask;
|
typedef unsigned long mask;
|
||||||
# elif defined(__EMSCRIPTEN__) || defined(__NetBSD__)
|
# elif defined(__EMSCRIPTEN__) || defined(__NetBSD__)
|
||||||
typedef unsigned short mask;
|
typedef unsigned short mask;
|
||||||
|
|||||||
2
lib/libcxx/include/locale
vendored
2
lib/libcxx/include/locale
vendored
@ -228,7 +228,7 @@ _LIBCPP_PUSH_MACROS
|
|||||||
|
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
# define _LIBCPP_GET_C_LOCALE 0
|
# define _LIBCPP_GET_C_LOCALE 0
|
||||||
#elif defined(__CloudABI__) || defined(__NetBSD__)
|
#elif defined(__CloudABI__) || defined(__NetBSD__)
|
||||||
# define _LIBCPP_GET_C_LOCALE LC_C_LOCALE
|
# define _LIBCPP_GET_C_LOCALE LC_C_LOCALE
|
||||||
|
|||||||
2
lib/libcxx/src/locale.cpp
vendored
2
lib/libcxx/src/locale.cpp
vendored
@ -1133,7 +1133,7 @@ ctype<char>::classic_table() noexcept
|
|||||||
const ctype<char>::mask*
|
const ctype<char>::mask*
|
||||||
ctype<char>::classic_table() noexcept
|
ctype<char>::classic_table() noexcept
|
||||||
{
|
{
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
return _DefaultRuneLocale.__runetype;
|
return _DefaultRuneLocale.__runetype;
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
return _C_ctype_tab_ + 1;
|
return _C_ctype_tab_ + 1;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! This API non-allocating, non-fallible, and thread-safe.
|
//! This API non-allocating, non-fallible, and thread-safe.
|
||||||
//! The tradeoff is that users of this API must provide the storage
|
//! The tradeoff is that users of this API must provide the storage
|
||||||
//! for each `Progress.Node`.
|
//! for each `Progress.Node`.
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2020 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! A software version formatted according to the Semantic Version 2 specification.
|
//! A software version formatted according to the Semantic Version 2 specification.
|
||||||
//!
|
//!
|
||||||
//! See: https://semver.org
|
//! See: https://semver.org
|
||||||
|
|||||||
@ -1,17 +1,12 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! This struct represents a kernel thread, and acts as a namespace for concurrency
|
//! This struct represents a kernel thread, and acts as a namespace for concurrency
|
||||||
//! primitives that operate on kernel threads. For concurrency primitives that support
|
//! primitives that operate on kernel threads. For concurrency primitives that support
|
||||||
//! both evented I/O and async I/O, see the respective names in the top level std namespace.
|
//! both evented I/O and async I/O, see the respective names in the top level std namespace.
|
||||||
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
|
const builtin = @import("builtin");
|
||||||
const os = std.os;
|
const os = std.os;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const target = std.Target.current;
|
const target = builtin.target;
|
||||||
const Atomic = std.atomic.Atomic;
|
const Atomic = std.atomic.Atomic;
|
||||||
|
|
||||||
pub const AutoResetEvent = @import("Thread/AutoResetEvent.zig");
|
pub const AutoResetEvent = @import("Thread/AutoResetEvent.zig");
|
||||||
@ -24,7 +19,8 @@ pub const Condition = @import("Thread/Condition.zig");
|
|||||||
|
|
||||||
pub const spinLoopHint = @compileError("deprecated: use std.atomic.spinLoopHint");
|
pub const spinLoopHint = @compileError("deprecated: use std.atomic.spinLoopHint");
|
||||||
|
|
||||||
pub const use_pthreads = target.os.tag != .windows and std.Target.current.os.tag != .wasi and std.builtin.link_libc;
|
pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc;
|
||||||
|
const is_gnu = target.abi.isGnu();
|
||||||
|
|
||||||
const Thread = @This();
|
const Thread = @This();
|
||||||
const Impl = if (target.os.tag == .windows)
|
const Impl = if (target.os.tag == .windows)
|
||||||
@ -38,7 +34,7 @@ else
|
|||||||
|
|
||||||
impl: Impl,
|
impl: Impl,
|
||||||
|
|
||||||
pub const max_name_len = switch (std.Target.current.os.tag) {
|
pub const max_name_len = switch (target.os.tag) {
|
||||||
.linux => 15,
|
.linux => 15,
|
||||||
.windows => 31,
|
.windows => 31,
|
||||||
.macos, .ios, .watchos, .tvos => 63,
|
.macos, .ios, .watchos, .tvos => 63,
|
||||||
@ -64,20 +60,21 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
break :blk name_buf[0..name.len :0];
|
break :blk name_buf[0..name.len :0];
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (std.Target.current.os.tag) {
|
switch (target.os.tag) {
|
||||||
.linux => if (use_pthreads) {
|
.linux => if (use_pthreads) {
|
||||||
const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr);
|
const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr);
|
||||||
return switch (err) {
|
switch (err) {
|
||||||
0 => {},
|
.SUCCESS => return,
|
||||||
os.ERANGE => unreachable,
|
.RANGE => unreachable,
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
} else if (use_pthreads and self.getHandle() == std.c.pthread_self()) {
|
} else if (use_pthreads and self.getHandle() == std.c.pthread_self()) {
|
||||||
|
// TODO: this is dead code. what did the author of this code intend to happen here?
|
||||||
const err = try os.prctl(.SET_NAME, .{@ptrToInt(name_with_terminator.ptr)});
|
const err = try os.prctl(.SET_NAME, .{@ptrToInt(name_with_terminator.ptr)});
|
||||||
return switch (err) {
|
switch (@intToEnum(os.E, err)) {
|
||||||
0 => {},
|
.SUCCESS => return,
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
var buf: [32]u8 = undefined;
|
var buf: [32]u8 = undefined;
|
||||||
const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
|
const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
|
||||||
@ -87,7 +84,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
|
|
||||||
try file.writer().writeAll(name);
|
try file.writer().writeAll(name);
|
||||||
},
|
},
|
||||||
.windows => if (std.Target.current.os.isAtLeast(.windows, .win10_rs1)) |res| {
|
.windows => if (target.os.isAtLeast(.windows, .win10_rs1)) |res| {
|
||||||
// SetThreadDescription is only available since version 1607, which is 10.0.14393.795
|
// SetThreadDescription is only available since version 1607, which is 10.0.14393.795
|
||||||
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
|
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
|
||||||
if (!res) {
|
if (!res) {
|
||||||
@ -110,24 +107,25 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
if (self.getHandle() != std.c.pthread_self()) return error.Unsupported;
|
if (self.getHandle() != std.c.pthread_self()) return error.Unsupported;
|
||||||
|
|
||||||
const err = std.c.pthread_setname_np(name_with_terminator.ptr);
|
const err = std.c.pthread_setname_np(name_with_terminator.ptr);
|
||||||
return switch (err) {
|
switch (err) {
|
||||||
0 => {},
|
.SUCCESS => return,
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
.netbsd => if (use_pthreads) {
|
.netbsd => if (use_pthreads) {
|
||||||
const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr, null);
|
const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr, null);
|
||||||
return switch (err) {
|
switch (err) {
|
||||||
0 => {},
|
.SUCCESS => return,
|
||||||
os.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
os.ESRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
os.ENOMEM => unreachable,
|
.NOMEM => unreachable,
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
.freebsd, .openbsd => if (use_pthreads) {
|
.freebsd, .openbsd => if (use_pthreads) {
|
||||||
// Use pthread_set_name_np for FreeBSD because pthread_setname_np is FreeBSD 12.2+ only.
|
// Use pthread_set_name_np for FreeBSD because pthread_setname_np is FreeBSD 12.2+ only.
|
||||||
// TODO maybe revisit this if depending on FreeBSD 12.2+ is acceptable because pthread_setname_np can return an error.
|
// TODO maybe revisit this if depending on FreeBSD 12.2+ is acceptable because
|
||||||
|
// pthread_setname_np can return an error.
|
||||||
|
|
||||||
std.c.pthread_set_name_np(self.getHandle(), name_with_terminator.ptr);
|
std.c.pthread_set_name_np(self.getHandle(), name_with_terminator.ptr);
|
||||||
},
|
},
|
||||||
@ -151,20 +149,20 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
buffer_ptr[max_name_len] = 0;
|
buffer_ptr[max_name_len] = 0;
|
||||||
var buffer = std.mem.span(buffer_ptr);
|
var buffer = std.mem.span(buffer_ptr);
|
||||||
|
|
||||||
switch (std.Target.current.os.tag) {
|
switch (target.os.tag) {
|
||||||
.linux => if (use_pthreads and comptime std.Target.current.abi.isGnu()) {
|
.linux => if (use_pthreads and is_gnu) {
|
||||||
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
||||||
return switch (err) {
|
switch (err) {
|
||||||
0 => std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
os.ERANGE => unreachable,
|
.RANGE => unreachable,
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
} else if (use_pthreads and self.getHandle() == std.c.pthread_self()) {
|
} else if (use_pthreads and self.getHandle() == std.c.pthread_self()) {
|
||||||
const err = try os.prctl(.GET_NAME, .{@ptrToInt(buffer.ptr)});
|
const err = try os.prctl(.GET_NAME, .{@ptrToInt(buffer.ptr)});
|
||||||
return switch (err) {
|
switch (@intToEnum(os.E, err)) {
|
||||||
0 => std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
} else if (!use_pthreads) {
|
} else if (!use_pthreads) {
|
||||||
var buf: [32]u8 = undefined;
|
var buf: [32]u8 = undefined;
|
||||||
const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
|
const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
|
||||||
@ -179,7 +177,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
// musl doesn't provide pthread_getname_np and there's no way to retrieve the thread id of an arbitrary thread.
|
// musl doesn't provide pthread_getname_np and there's no way to retrieve the thread id of an arbitrary thread.
|
||||||
return error.Unsupported;
|
return error.Unsupported;
|
||||||
},
|
},
|
||||||
.windows => if (std.Target.current.os.isAtLeast(.windows, .win10_rs1)) |res| {
|
.windows => if (target.os.isAtLeast(.windows, .win10_rs1)) |res| {
|
||||||
// GetThreadDescription is only available since version 1607, which is 10.0.14393.795
|
// GetThreadDescription is only available since version 1607, which is 10.0.14393.795
|
||||||
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
|
// See https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
|
||||||
if (!res) {
|
if (!res) {
|
||||||
@ -198,20 +196,20 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
},
|
},
|
||||||
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
|
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
|
||||||
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
||||||
return switch (err) {
|
switch (err) {
|
||||||
0 => std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
os.ESRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
.netbsd => if (use_pthreads) {
|
.netbsd => if (use_pthreads) {
|
||||||
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
||||||
return switch (err) {
|
switch (err) {
|
||||||
0 => std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
os.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
os.ESRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
else => return os.unexpectedErrno(err),
|
else => |e| return os.unexpectedErrno(e),
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
.freebsd, .openbsd => if (use_pthreads) {
|
.freebsd, .openbsd => if (use_pthreads) {
|
||||||
// Use pthread_get_name_np for FreeBSD because pthread_getname_np is FreeBSD 12.2+ only.
|
// Use pthread_get_name_np for FreeBSD because pthread_getname_np is FreeBSD 12.2+ only.
|
||||||
@ -288,7 +286,7 @@ pub const SpawnError = error{
|
|||||||
/// The caller must eventually either call `join()` to wait for the thread to finish and free its resources
|
/// The caller must eventually either call `join()` to wait for the thread to finish and free its resources
|
||||||
/// or call `detach()` to excuse the caller from calling `join()` and have the thread clean up its resources on completion`.
|
/// or call `detach()` to excuse the caller from calling `join()` and have the thread clean up its resources on completion`.
|
||||||
pub fn spawn(config: SpawnConfig, comptime function: anytype, args: anytype) SpawnError!Thread {
|
pub fn spawn(config: SpawnConfig, comptime function: anytype, args: anytype) SpawnError!Thread {
|
||||||
if (std.builtin.single_threaded) {
|
if (builtin.single_threaded) {
|
||||||
@compileError("Cannot spawn thread when building in single-threaded mode");
|
@compileError("Cannot spawn thread when building in single-threaded mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,13 +609,13 @@ const PosixThreadImpl = struct {
|
|||||||
errdefer allocator.destroy(args_ptr);
|
errdefer allocator.destroy(args_ptr);
|
||||||
|
|
||||||
var attr: c.pthread_attr_t = undefined;
|
var attr: c.pthread_attr_t = undefined;
|
||||||
if (c.pthread_attr_init(&attr) != 0) return error.SystemResources;
|
if (c.pthread_attr_init(&attr) != .SUCCESS) return error.SystemResources;
|
||||||
defer assert(c.pthread_attr_destroy(&attr) == 0);
|
defer assert(c.pthread_attr_destroy(&attr) == .SUCCESS);
|
||||||
|
|
||||||
// Use the same set of parameters used by the libc-less impl.
|
// Use the same set of parameters used by the libc-less impl.
|
||||||
const stack_size = std.math.max(config.stack_size, 16 * 1024);
|
const stack_size = std.math.max(config.stack_size, 16 * 1024);
|
||||||
assert(c.pthread_attr_setstacksize(&attr, stack_size) == 0);
|
assert(c.pthread_attr_setstacksize(&attr, stack_size) == .SUCCESS);
|
||||||
assert(c.pthread_attr_setguardsize(&attr, std.mem.page_size) == 0);
|
assert(c.pthread_attr_setguardsize(&attr, std.mem.page_size) == .SUCCESS);
|
||||||
|
|
||||||
var handle: c.pthread_t = undefined;
|
var handle: c.pthread_t = undefined;
|
||||||
switch (c.pthread_create(
|
switch (c.pthread_create(
|
||||||
@ -626,10 +624,10 @@ const PosixThreadImpl = struct {
|
|||||||
Instance.entryFn,
|
Instance.entryFn,
|
||||||
if (@sizeOf(Args) > 1) @ptrCast(*c_void, args_ptr) else undefined,
|
if (@sizeOf(Args) > 1) @ptrCast(*c_void, args_ptr) else undefined,
|
||||||
)) {
|
)) {
|
||||||
0 => return Impl{ .handle = handle },
|
.SUCCESS => return Impl{ .handle = handle },
|
||||||
os.EAGAIN => return error.SystemResources,
|
.AGAIN => return error.SystemResources,
|
||||||
os.EPERM => unreachable,
|
.PERM => unreachable,
|
||||||
os.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
else => |err| return os.unexpectedErrno(err),
|
else => |err| return os.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -640,19 +638,19 @@ const PosixThreadImpl = struct {
|
|||||||
|
|
||||||
fn detach(self: Impl) void {
|
fn detach(self: Impl) void {
|
||||||
switch (c.pthread_detach(self.handle)) {
|
switch (c.pthread_detach(self.handle)) {
|
||||||
0 => {},
|
.SUCCESS => {},
|
||||||
os.EINVAL => unreachable, // thread handle is not joinable
|
.INVAL => unreachable, // thread handle is not joinable
|
||||||
os.ESRCH => unreachable, // thread handle is invalid
|
.SRCH => unreachable, // thread handle is invalid
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join(self: Impl) void {
|
fn join(self: Impl) void {
|
||||||
switch (c.pthread_join(self.handle, null)) {
|
switch (c.pthread_join(self.handle, null)) {
|
||||||
0 => {},
|
.SUCCESS => {},
|
||||||
os.EINVAL => unreachable, // thread handle is not joinable (or another thread is already joining in)
|
.INVAL => unreachable, // thread handle is not joinable (or another thread is already joining in)
|
||||||
os.ESRCH => unreachable, // thread handle is invalid
|
.SRCH => unreachable, // thread handle is invalid
|
||||||
os.EDEADLK => unreachable, // two threads tried to join each other
|
.DEADLK => unreachable, // two threads tried to join each other
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -806,8 +804,10 @@ const LinuxThreadImpl = struct {
|
|||||||
\\ 1:
|
\\ 1:
|
||||||
\\ cmp %%sp, 0
|
\\ cmp %%sp, 0
|
||||||
\\ beq 2f
|
\\ beq 2f
|
||||||
|
\\ nop
|
||||||
\\ restore
|
\\ restore
|
||||||
\\ ba 1f
|
\\ ba 1f
|
||||||
|
\\ nop
|
||||||
\\ 2:
|
\\ 2:
|
||||||
\\ mov 73, %%g1
|
\\ mov 73, %%g1
|
||||||
\\ mov %[ptr], %%o0
|
\\ mov %[ptr], %%o0
|
||||||
@ -937,13 +937,13 @@ const LinuxThreadImpl = struct {
|
|||||||
tls_ptr,
|
tls_ptr,
|
||||||
&instance.thread.child_tid.value,
|
&instance.thread.child_tid.value,
|
||||||
))) {
|
))) {
|
||||||
0 => return Impl{ .thread = &instance.thread },
|
.SUCCESS => return Impl{ .thread = &instance.thread },
|
||||||
os.EAGAIN => return error.ThreadQuotaExceeded,
|
.AGAIN => return error.ThreadQuotaExceeded,
|
||||||
os.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
os.ENOMEM => return error.SystemResources,
|
.NOMEM => return error.SystemResources,
|
||||||
os.ENOSPC => unreachable,
|
.NOSPC => unreachable,
|
||||||
os.EPERM => unreachable,
|
.PERM => unreachable,
|
||||||
os.EUSERS => unreachable,
|
.USERS => unreachable,
|
||||||
else => |err| return os.unexpectedErrno(err),
|
else => |err| return os.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -982,9 +982,9 @@ const LinuxThreadImpl = struct {
|
|||||||
tid,
|
tid,
|
||||||
null,
|
null,
|
||||||
))) {
|
))) {
|
||||||
0 => continue,
|
.SUCCESS => continue,
|
||||||
os.EINTR => continue,
|
.INTR => continue,
|
||||||
os.EAGAIN => continue,
|
.AGAIN => continue,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1011,7 +1011,7 @@ fn testThreadName(thread: *Thread) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "setName, getName" {
|
test "setName, getName" {
|
||||||
if (std.builtin.single_threaded) return error.SkipZigTest;
|
if (builtin.single_threaded) return error.SkipZigTest;
|
||||||
|
|
||||||
const Context = struct {
|
const Context = struct {
|
||||||
start_wait_event: ResetEvent = undefined,
|
start_wait_event: ResetEvent = undefined,
|
||||||
@ -1029,7 +1029,7 @@ test "setName, getName" {
|
|||||||
// Wait for the main thread to have set the thread field in the context.
|
// Wait for the main thread to have set the thread field in the context.
|
||||||
ctx.start_wait_event.wait();
|
ctx.start_wait_event.wait();
|
||||||
|
|
||||||
switch (std.Target.current.os.tag) {
|
switch (target.os.tag) {
|
||||||
.windows => testThreadName(&ctx.thread) catch |err| switch (err) {
|
.windows => testThreadName(&ctx.thread) catch |err| switch (err) {
|
||||||
error.Unsupported => return error.SkipZigTest,
|
error.Unsupported => return error.SkipZigTest,
|
||||||
else => return err,
|
else => return err,
|
||||||
@ -1054,7 +1054,7 @@ test "setName, getName" {
|
|||||||
context.start_wait_event.set();
|
context.start_wait_event.set();
|
||||||
context.test_done_event.wait();
|
context.test_done_event.wait();
|
||||||
|
|
||||||
switch (std.Target.current.os.tag) {
|
switch (target.os.tag) {
|
||||||
.macos, .ios, .watchos, .tvos => {
|
.macos, .ios, .watchos, .tvos => {
|
||||||
const res = thread.setName("foobar");
|
const res = thread.setName("foobar");
|
||||||
try std.testing.expectError(error.Unsupported, res);
|
try std.testing.expectError(error.Unsupported, res);
|
||||||
@ -1063,7 +1063,7 @@ test "setName, getName" {
|
|||||||
error.Unsupported => return error.SkipZigTest,
|
error.Unsupported => return error.SkipZigTest,
|
||||||
else => return err,
|
else => return err,
|
||||||
},
|
},
|
||||||
else => |tag| if (tag == .linux and use_pthreads and comptime std.Target.current.abi.isMusl()) {
|
else => |tag| if (tag == .linux and use_pthreads and comptime target.abi.isMusl()) {
|
||||||
try thread.setName("foobar");
|
try thread.setName("foobar");
|
||||||
|
|
||||||
var name_buffer: [max_name_len:0]u8 = undefined;
|
var name_buffer: [max_name_len:0]u8 = undefined;
|
||||||
@ -1096,7 +1096,7 @@ fn testIncrementNotify(value: *usize, event: *ResetEvent) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "Thread.join" {
|
test "Thread.join" {
|
||||||
if (std.builtin.single_threaded) return error.SkipZigTest;
|
if (builtin.single_threaded) return error.SkipZigTest;
|
||||||
|
|
||||||
var value: usize = 0;
|
var value: usize = 0;
|
||||||
var event: ResetEvent = undefined;
|
var event: ResetEvent = undefined;
|
||||||
@ -1110,7 +1110,7 @@ test "Thread.join" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "Thread.detach" {
|
test "Thread.detach" {
|
||||||
if (std.builtin.single_threaded) return error.SkipZigTest;
|
if (builtin.single_threaded) return error.SkipZigTest;
|
||||||
|
|
||||||
var value: usize = 0;
|
var value: usize = 0;
|
||||||
var event: ResetEvent = undefined;
|
var event: ResetEvent = undefined;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! Similar to `StaticResetEvent` but on `set()` it also (atomically) does `reset()`.
|
//! Similar to `StaticResetEvent` but on `set()` it also (atomically) does `reset()`.
|
||||||
//! Unlike StaticResetEvent, `wait()` can only be called by one thread (MPSC-like).
|
//! Unlike StaticResetEvent, `wait()` can only be called by one thread (MPSC-like).
|
||||||
//!
|
//!
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! A condition provides a way for a kernel thread to block until it is signaled
|
//! A condition provides a way for a kernel thread to block until it is signaled
|
||||||
//! to wake up. Spurious wakeups are possible.
|
//! to wake up. Spurious wakeups are possible.
|
||||||
//! This API supports static initialization and does not require deinitialization.
|
//! This API supports static initialization and does not require deinitialization.
|
||||||
@ -81,17 +75,17 @@ pub const PthreadCondition = struct {
|
|||||||
|
|
||||||
pub fn wait(cond: *PthreadCondition, mutex: *Mutex) void {
|
pub fn wait(cond: *PthreadCondition, mutex: *Mutex) void {
|
||||||
const rc = std.c.pthread_cond_wait(&cond.cond, &mutex.impl.pthread_mutex);
|
const rc = std.c.pthread_cond_wait(&cond.cond, &mutex.impl.pthread_mutex);
|
||||||
assert(rc == 0);
|
assert(rc == .SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signal(cond: *PthreadCondition) void {
|
pub fn signal(cond: *PthreadCondition) void {
|
||||||
const rc = std.c.pthread_cond_signal(&cond.cond);
|
const rc = std.c.pthread_cond_signal(&cond.cond);
|
||||||
assert(rc == 0);
|
assert(rc == .SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn broadcast(cond: *PthreadCondition) void {
|
pub fn broadcast(cond: *PthreadCondition) void {
|
||||||
const rc = std.c.pthread_cond_broadcast(&cond.cond);
|
const rc = std.c.pthread_cond_broadcast(&cond.cond);
|
||||||
assert(rc == 0);
|
assert(rc == .SUCCESS);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,9 +109,9 @@ pub const AtomicCondition = struct {
|
|||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
))) {
|
))) {
|
||||||
0 => {},
|
.SUCCESS => {},
|
||||||
std.os.EINTR => {},
|
.INTR => {},
|
||||||
std.os.EAGAIN => {},
|
.AGAIN => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -136,8 +130,8 @@ pub const AtomicCondition = struct {
|
|||||||
linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAKE,
|
linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAKE,
|
||||||
1,
|
1,
|
||||||
))) {
|
))) {
|
||||||
0 => {},
|
.SUCCESS => {},
|
||||||
std.os.EFAULT => {},
|
.FAULT => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! Futex is a mechanism used to block (`wait`) and unblock (`wake`) threads using a 32bit memory address as hints.
|
//! Futex is a mechanism used to block (`wait`) and unblock (`wake`) threads using a 32bit memory address as hints.
|
||||||
//! Blocking a thread is acknowledged only if the 32bit memory address is equal to a given value.
|
//! Blocking a thread is acknowledged only if the 32bit memory address is equal to a given value.
|
||||||
//! This check helps avoid block/unblock deadlocks which occur if a `wake()` happens before a `wait()`.
|
//! This check helps avoid block/unblock deadlocks which occur if a `wake()` happens before a `wait()`.
|
||||||
@ -152,12 +146,12 @@ const LinuxFutex = struct {
|
|||||||
@bitCast(i32, expect),
|
@bitCast(i32, expect),
|
||||||
ts_ptr,
|
ts_ptr,
|
||||||
))) {
|
))) {
|
||||||
0 => {}, // notified by `wake()`
|
.SUCCESS => {}, // notified by `wake()`
|
||||||
std.os.EINTR => {}, // spurious wakeup
|
.INTR => {}, // spurious wakeup
|
||||||
std.os.EAGAIN => {}, // ptr.* != expect
|
.AGAIN => {}, // ptr.* != expect
|
||||||
std.os.ETIMEDOUT => return error.TimedOut,
|
.TIMEDOUT => return error.TimedOut,
|
||||||
std.os.EINVAL => {}, // possibly timeout overflow
|
.INVAL => {}, // possibly timeout overflow
|
||||||
std.os.EFAULT => unreachable,
|
.FAULT => unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,9 +162,9 @@ const LinuxFutex = struct {
|
|||||||
linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAKE,
|
linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAKE,
|
||||||
std.math.cast(i32, num_waiters) catch std.math.maxInt(i32),
|
std.math.cast(i32, num_waiters) catch std.math.maxInt(i32),
|
||||||
))) {
|
))) {
|
||||||
0 => {}, // successful wake up
|
.SUCCESS => {}, // successful wake up
|
||||||
std.os.EINVAL => {}, // invalid futex_wait() on ptr done elsewhere
|
.INVAL => {}, // invalid futex_wait() on ptr done elsewhere
|
||||||
std.os.EFAULT => {}, // pointer became invalid while doing the wake
|
.FAULT => {}, // pointer became invalid while doing the wake
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,13 +209,13 @@ const DarwinFutex = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (status >= 0) return;
|
if (status >= 0) return;
|
||||||
switch (-status) {
|
switch (@intToEnum(std.os.E, -status)) {
|
||||||
darwin.EINTR => {},
|
.INTR => {},
|
||||||
// Address of the futex is paged out. This is unlikely, but possible in theory, and
|
// Address of the futex is paged out. This is unlikely, but possible in theory, and
|
||||||
// pthread/libdispatch on darwin bother to handle it. In this case we'll return
|
// pthread/libdispatch on darwin bother to handle it. In this case we'll return
|
||||||
// without waiting, but the caller should retry anyway.
|
// without waiting, but the caller should retry anyway.
|
||||||
darwin.EFAULT => {},
|
.FAULT => {},
|
||||||
darwin.ETIMEDOUT => if (!timeout_overflowed) return error.TimedOut,
|
.TIMEDOUT => if (!timeout_overflowed) return error.TimedOut,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,11 +231,11 @@ const DarwinFutex = struct {
|
|||||||
const status = darwin.__ulock_wake(flags, addr, 0);
|
const status = darwin.__ulock_wake(flags, addr, 0);
|
||||||
|
|
||||||
if (status >= 0) return;
|
if (status >= 0) return;
|
||||||
switch (-status) {
|
switch (@intToEnum(std.os.E, -status)) {
|
||||||
darwin.EINTR => continue, // spurious wake()
|
.INTR => continue, // spurious wake()
|
||||||
darwin.EFAULT => continue, // address of the lock was paged out
|
.FAULT => continue, // address of the lock was paged out
|
||||||
darwin.ENOENT => return, // nothing was woken up
|
.NOENT => return, // nothing was woken up
|
||||||
darwin.EALREADY => unreachable, // only for ULF_WAKE_THREAD
|
.ALREADY => unreachable, // only for ULF_WAKE_THREAD
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,8 +249,8 @@ const PosixFutex = struct {
|
|||||||
var waiter: List.Node = undefined;
|
var waiter: List.Node = undefined;
|
||||||
|
|
||||||
{
|
{
|
||||||
assert(std.c.pthread_mutex_lock(&bucket.mutex) == 0);
|
assert(std.c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == 0);
|
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
||||||
|
|
||||||
if (ptr.load(.SeqCst) != expect) {
|
if (ptr.load(.SeqCst) != expect) {
|
||||||
return;
|
return;
|
||||||
@ -272,8 +266,8 @@ const PosixFutex = struct {
|
|||||||
waiter.data.wait(null) catch unreachable;
|
waiter.data.wait(null) catch unreachable;
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(std.c.pthread_mutex_lock(&bucket.mutex) == 0);
|
assert(std.c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == 0);
|
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
||||||
|
|
||||||
if (waiter.data.address == address) {
|
if (waiter.data.address == address) {
|
||||||
timed_out = true;
|
timed_out = true;
|
||||||
@ -297,8 +291,8 @@ const PosixFutex = struct {
|
|||||||
waiter.data.notify();
|
waiter.data.notify();
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(std.c.pthread_mutex_lock(&bucket.mutex) == 0);
|
assert(std.c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == 0);
|
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
||||||
|
|
||||||
var waiters = bucket.list.first;
|
var waiters = bucket.list.first;
|
||||||
while (waiters) |waiter| {
|
while (waiters) |waiter| {
|
||||||
@ -340,16 +334,13 @@ const PosixFutex = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn deinit(self: *Self) void {
|
fn deinit(self: *Self) void {
|
||||||
const rc = std.c.pthread_cond_destroy(&self.cond);
|
_ = std.c.pthread_cond_destroy(&self.cond);
|
||||||
assert(rc == 0 or rc == std.os.EINVAL);
|
_ = std.c.pthread_mutex_destroy(&self.mutex);
|
||||||
|
|
||||||
const rm = std.c.pthread_mutex_destroy(&self.mutex);
|
|
||||||
assert(rm == 0 or rm == std.os.EINVAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(self: *Self, timeout: ?u64) error{TimedOut}!void {
|
fn wait(self: *Self, timeout: ?u64) error{TimedOut}!void {
|
||||||
assert(std.c.pthread_mutex_lock(&self.mutex) == 0);
|
assert(std.c.pthread_mutex_lock(&self.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&self.mutex) == 0);
|
defer assert(std.c.pthread_mutex_unlock(&self.mutex) == .SUCCESS);
|
||||||
|
|
||||||
switch (self.state) {
|
switch (self.state) {
|
||||||
.empty => self.state = .waiting,
|
.empty => self.state = .waiting,
|
||||||
@ -378,28 +369,31 @@ const PosixFutex = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ts_ref = ts_ptr orelse {
|
const ts_ref = ts_ptr orelse {
|
||||||
assert(std.c.pthread_cond_wait(&self.cond, &self.mutex) == 0);
|
assert(std.c.pthread_cond_wait(&self.cond, &self.mutex) == .SUCCESS);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rc = std.c.pthread_cond_timedwait(&self.cond, &self.mutex, ts_ref);
|
const rc = std.c.pthread_cond_timedwait(&self.cond, &self.mutex, ts_ref);
|
||||||
assert(rc == 0 or rc == std.os.ETIMEDOUT);
|
switch (rc) {
|
||||||
if (rc == std.os.ETIMEDOUT) {
|
.SUCCESS => {},
|
||||||
self.state = .empty;
|
.TIMEDOUT => {
|
||||||
return error.TimedOut;
|
self.state = .empty;
|
||||||
|
return error.TimedOut;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify(self: *Self) void {
|
fn notify(self: *Self) void {
|
||||||
assert(std.c.pthread_mutex_lock(&self.mutex) == 0);
|
assert(std.c.pthread_mutex_lock(&self.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&self.mutex) == 0);
|
defer assert(std.c.pthread_mutex_unlock(&self.mutex) == .SUCCESS);
|
||||||
|
|
||||||
switch (self.state) {
|
switch (self.state) {
|
||||||
.empty => self.state = .notified,
|
.empty => self.state = .notified,
|
||||||
.waiting => {
|
.waiting => {
|
||||||
self.state = .notified;
|
self.state = .notified;
|
||||||
assert(std.c.pthread_cond_signal(&self.cond) == 0);
|
assert(std.c.pthread_cond_signal(&self.cond) == .SUCCESS);
|
||||||
},
|
},
|
||||||
.notified => unreachable,
|
.notified => unreachable,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! Lock may be held only once. If the same thread tries to acquire
|
//! Lock may be held only once. If the same thread tries to acquire
|
||||||
//! the same mutex twice, it deadlocks. This type supports static
|
//! the same mutex twice, it deadlocks. This type supports static
|
||||||
//! initialization and is at most `@sizeOf(usize)` in size. When an
|
//! initialization and is at most `@sizeOf(usize)` in size. When an
|
||||||
@ -143,9 +137,9 @@ pub const AtomicMutex = struct {
|
|||||||
@enumToInt(new_state),
|
@enumToInt(new_state),
|
||||||
null,
|
null,
|
||||||
))) {
|
))) {
|
||||||
0 => {},
|
.SUCCESS => {},
|
||||||
std.os.EINTR => {},
|
.INTR => {},
|
||||||
std.os.EAGAIN => {},
|
.AGAIN => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -164,8 +158,8 @@ pub const AtomicMutex = struct {
|
|||||||
linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAKE,
|
linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAKE,
|
||||||
1,
|
1,
|
||||||
))) {
|
))) {
|
||||||
0 => {},
|
.SUCCESS => {},
|
||||||
std.os.EFAULT => {},
|
.FAULT => unreachable, // invalid pointer passed to futex_wake
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -182,10 +176,10 @@ pub const PthreadMutex = struct {
|
|||||||
|
|
||||||
pub fn release(held: Held) void {
|
pub fn release(held: Held) void {
|
||||||
switch (std.c.pthread_mutex_unlock(&held.mutex.pthread_mutex)) {
|
switch (std.c.pthread_mutex_unlock(&held.mutex.pthread_mutex)) {
|
||||||
0 => return,
|
.SUCCESS => return,
|
||||||
std.c.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
std.c.EAGAIN => unreachable,
|
.AGAIN => unreachable,
|
||||||
std.c.EPERM => unreachable,
|
.PERM => unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +189,7 @@ pub const PthreadMutex = struct {
|
|||||||
/// the mutex is unavailable. Otherwise returns Held. Call
|
/// the mutex is unavailable. Otherwise returns Held. Call
|
||||||
/// release on Held.
|
/// release on Held.
|
||||||
pub fn tryAcquire(m: *PthreadMutex) ?Held {
|
pub fn tryAcquire(m: *PthreadMutex) ?Held {
|
||||||
if (std.c.pthread_mutex_trylock(&m.pthread_mutex) == 0) {
|
if (std.c.pthread_mutex_trylock(&m.pthread_mutex) == .SUCCESS) {
|
||||||
return Held{ .mutex = m };
|
return Held{ .mutex = m };
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
@ -206,12 +200,12 @@ pub const PthreadMutex = struct {
|
|||||||
/// held by the calling thread.
|
/// held by the calling thread.
|
||||||
pub fn acquire(m: *PthreadMutex) Held {
|
pub fn acquire(m: *PthreadMutex) Held {
|
||||||
switch (std.c.pthread_mutex_lock(&m.pthread_mutex)) {
|
switch (std.c.pthread_mutex_lock(&m.pthread_mutex)) {
|
||||||
0 => return Held{ .mutex = m },
|
.SUCCESS => return Held{ .mutex = m },
|
||||||
std.c.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
std.c.EBUSY => unreachable,
|
.BUSY => unreachable,
|
||||||
std.c.EAGAIN => unreachable,
|
.AGAIN => unreachable,
|
||||||
std.c.EDEADLK => unreachable,
|
.DEADLK => unreachable,
|
||||||
std.c.EPERM => unreachable,
|
.PERM => unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! A thread-safe resource which supports blocking until signaled.
|
//! A thread-safe resource which supports blocking until signaled.
|
||||||
//! This API is for kernel threads, not evented I/O.
|
//! This API is for kernel threads, not evented I/O.
|
||||||
//! This API requires being initialized at runtime, and initialization
|
//! This API requires being initialized at runtime, and initialization
|
||||||
@ -130,7 +124,7 @@ pub const PosixEvent = struct {
|
|||||||
|
|
||||||
pub fn init(ev: *PosixEvent) !void {
|
pub fn init(ev: *PosixEvent) !void {
|
||||||
switch (c.getErrno(c.sem_init(&ev.sem, 0, 0))) {
|
switch (c.getErrno(c.sem_init(&ev.sem, 0, 0))) {
|
||||||
0 => return,
|
.SUCCESS => return,
|
||||||
else => return error.SystemResources,
|
else => return error.SystemResources,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,9 +141,9 @@ pub const PosixEvent = struct {
|
|||||||
pub fn wait(ev: *PosixEvent) void {
|
pub fn wait(ev: *PosixEvent) void {
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (c.getErrno(c.sem_wait(&ev.sem))) {
|
switch (c.getErrno(c.sem_wait(&ev.sem))) {
|
||||||
0 => return,
|
.SUCCESS => return,
|
||||||
c.EINTR => continue,
|
.INTR => continue,
|
||||||
c.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,10 +159,10 @@ pub const PosixEvent = struct {
|
|||||||
ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.ns_per_s));
|
ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.ns_per_s));
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (c.getErrno(c.sem_timedwait(&ev.sem, &ts))) {
|
switch (c.getErrno(c.sem_timedwait(&ev.sem, &ts))) {
|
||||||
0 => return .event_set,
|
.SUCCESS => return .event_set,
|
||||||
c.EINTR => continue,
|
.INTR => continue,
|
||||||
c.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
c.ETIMEDOUT => return .timed_out,
|
.TIMEDOUT => return .timed_out,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,10 +171,10 @@ pub const PosixEvent = struct {
|
|||||||
pub fn reset(ev: *PosixEvent) void {
|
pub fn reset(ev: *PosixEvent) void {
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (c.getErrno(c.sem_trywait(&ev.sem))) {
|
switch (c.getErrno(c.sem_trywait(&ev.sem))) {
|
||||||
0 => continue, // Need to make it go to zero.
|
.SUCCESS => continue, // Need to make it go to zero.
|
||||||
c.EINTR => continue,
|
.INTR => continue,
|
||||||
c.EINVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
c.EAGAIN => return, // The semaphore currently has the value zero.
|
.AGAIN => return, // The semaphore currently has the value zero.
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! A lock that supports one writer or many readers.
|
//! A lock that supports one writer or many readers.
|
||||||
//! This API is for kernel threads, not evented I/O.
|
//! This API is for kernel threads, not evented I/O.
|
||||||
//! This API requires being initialized at runtime, and initialization
|
//! This API requires being initialized at runtime, and initialization
|
||||||
@ -13,7 +7,7 @@ impl: Impl,
|
|||||||
|
|
||||||
const RwLock = @This();
|
const RwLock = @This();
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = std.builtin;
|
const builtin = @import("builtin");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Mutex = std.Thread.Mutex;
|
const Mutex = std.Thread.Mutex;
|
||||||
const Semaphore = std.Semaphore;
|
const Semaphore = std.Semaphore;
|
||||||
@ -165,43 +159,41 @@ pub const PthreadRwLock = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(rwl: *PthreadRwLock) void {
|
pub fn deinit(rwl: *PthreadRwLock) void {
|
||||||
const safe_rc = switch (std.builtin.os.tag) {
|
const safe_rc: std.os.E = switch (builtin.os.tag) {
|
||||||
.dragonfly, .netbsd => std.os.EAGAIN,
|
.dragonfly, .netbsd => .AGAIN,
|
||||||
else => 0,
|
else => .SUCCESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
const rc = std.c.pthread_rwlock_destroy(&rwl.rwlock);
|
const rc = std.c.pthread_rwlock_destroy(&rwl.rwlock);
|
||||||
assert(rc == 0 or rc == safe_rc);
|
assert(rc == .SUCCESS or rc == safe_rc);
|
||||||
|
|
||||||
rwl.* = undefined;
|
rwl.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tryLock(rwl: *PthreadRwLock) bool {
|
pub fn tryLock(rwl: *PthreadRwLock) bool {
|
||||||
return pthread_rwlock_trywrlock(&rwl.rwlock) == 0;
|
return pthread_rwlock_trywrlock(&rwl.rwlock) == .SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lock(rwl: *PthreadRwLock) void {
|
pub fn lock(rwl: *PthreadRwLock) void {
|
||||||
const rc = pthread_rwlock_wrlock(&rwl.rwlock);
|
const rc = pthread_rwlock_wrlock(&rwl.rwlock);
|
||||||
assert(rc == 0);
|
assert(rc == .SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlock(rwl: *PthreadRwLock) void {
|
pub fn unlock(rwl: *PthreadRwLock) void {
|
||||||
const rc = pthread_rwlock_unlock(&rwl.rwlock);
|
const rc = pthread_rwlock_unlock(&rwl.rwlock);
|
||||||
assert(rc == 0);
|
assert(rc == .SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tryLockShared(rwl: *PthreadRwLock) bool {
|
pub fn tryLockShared(rwl: *PthreadRwLock) bool {
|
||||||
return pthread_rwlock_tryrdlock(&rwl.rwlock) == 0;
|
return pthread_rwlock_tryrdlock(&rwl.rwlock) == .SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lockShared(rwl: *PthreadRwLock) void {
|
pub fn lockShared(rwl: *PthreadRwLock) void {
|
||||||
const rc = pthread_rwlock_rdlock(&rwl.rwlock);
|
const rc = pthread_rwlock_rdlock(&rwl.rwlock);
|
||||||
assert(rc == 0);
|
assert(rc == .SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlockShared(rwl: *PthreadRwLock) void {
|
pub fn unlockShared(rwl: *PthreadRwLock) void {
|
||||||
const rc = pthread_rwlock_unlock(&rwl.rwlock);
|
const rc = pthread_rwlock_unlock(&rwl.rwlock);
|
||||||
assert(rc == 0);
|
assert(rc == .SUCCESS);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! A semaphore is an unsigned integer that blocks the kernel thread if
|
//! A semaphore is an unsigned integer that blocks the kernel thread if
|
||||||
//! the number would become negative.
|
//! the number would become negative.
|
||||||
//! This API supports static initialization and does not require deinitialization.
|
//! This API supports static initialization and does not require deinitialization.
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! A thread-safe resource which supports blocking until signaled.
|
//! A thread-safe resource which supports blocking until signaled.
|
||||||
//! This API is for kernel threads, not evented I/O.
|
//! This API is for kernel threads, not evented I/O.
|
||||||
//! This API is statically initializable. It cannot fail to be initialized
|
//! This API is statically initializable. It cannot fail to be initialized
|
||||||
@ -201,7 +195,7 @@ pub const AtomicEvent = struct {
|
|||||||
const waiting = std.math.maxInt(i32); // wake_count
|
const waiting = std.math.maxInt(i32); // wake_count
|
||||||
const ptr = @ptrCast(*const i32, waiters);
|
const ptr = @ptrCast(*const i32, waiters);
|
||||||
const rc = linux.futex_wake(ptr, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, waiting);
|
const rc = linux.futex_wake(ptr, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, waiting);
|
||||||
assert(linux.getErrno(rc) == 0);
|
assert(linux.getErrno(rc) == .SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(waiters: *u32, timeout: ?u64) !void {
|
fn wait(waiters: *u32, timeout: ?u64) !void {
|
||||||
@ -221,10 +215,10 @@ pub const AtomicEvent = struct {
|
|||||||
const ptr = @ptrCast(*const i32, waiters);
|
const ptr = @ptrCast(*const i32, waiters);
|
||||||
const rc = linux.futex_wait(ptr, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, expected, ts_ptr);
|
const rc = linux.futex_wait(ptr, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, expected, ts_ptr);
|
||||||
switch (linux.getErrno(rc)) {
|
switch (linux.getErrno(rc)) {
|
||||||
0 => continue,
|
.SUCCESS => continue,
|
||||||
os.ETIMEDOUT => return error.TimedOut,
|
.TIMEDOUT => return error.TimedOut,
|
||||||
os.EINTR => continue,
|
.INTR => continue,
|
||||||
os.EAGAIN => return,
|
.AGAIN => return,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const assert = debug.assert;
|
const assert = debug.assert;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const assert = debug.assert;
|
const assert = debug.assert;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
// Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does.
|
// Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does.
|
||||||
// I could have taken only a u7 to make this clear, but it would be slower
|
// I could have taken only a u7 to make this clear, but it would be slower
|
||||||
// It is my opinion that encodings other than UTF-8 should not be supported.
|
// It is my opinion that encodings other than UTF-8 should not be supported.
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const target = std.Target.current;
|
const target = std.Target.current;
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const expect = std.testing.expect;
|
const expect = std.testing.expect;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//! This file defines several variants of bit sets. A bit set
|
//! This file defines several variants of bit sets. A bit set
|
||||||
//! is a densely stored set of integers with a known maximum,
|
//! is a densely stored set of integers with a known maximum,
|
||||||
//! in which each integer gets a single bit. Bit sets have very
|
//! in which each integer gets a single bit. Bit sets have very
|
||||||
|
|||||||
315
lib/std/bounded_array.zig
Normal file
315
lib/std/bounded_array.zig
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
const std = @import("std.zig");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const mem = std.mem;
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
/// A structure with an array and a length, that can be used as a slice.
|
||||||
|
///
|
||||||
|
/// Useful to pass around small arrays whose exact size is only known at
|
||||||
|
/// runtime, but whose maximum size is known at comptime, without requiring
|
||||||
|
/// an `Allocator`.
|
||||||
|
///
|
||||||
|
/// ```zig
|
||||||
|
/// var actual_size = 32;
|
||||||
|
/// var a = try BoundedArray(u8, 64).init(actual_size);
|
||||||
|
/// var slice = a.slice(); // a slice of the 64-byte array
|
||||||
|
/// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers
|
||||||
|
/// ```
|
||||||
|
pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
buffer: [capacity]T,
|
||||||
|
len: usize = 0,
|
||||||
|
|
||||||
|
/// Set the actual length of the slice.
|
||||||
|
/// Returns error.Overflow if it exceeds the length of the backing array.
|
||||||
|
pub fn init(len: usize) !Self {
|
||||||
|
if (len > capacity) return error.Overflow;
|
||||||
|
return Self{ .buffer = undefined, .len = len };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// View the internal array as a mutable slice whose size was previously set.
|
||||||
|
pub fn slice(self: *Self) []T {
|
||||||
|
return self.buffer[0..self.len];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// View the internal array as a constant slice whose size was previously set.
|
||||||
|
pub fn constSlice(self: Self) []const T {
|
||||||
|
return self.buffer[0..self.len];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adjust the slice's length to `len`.
|
||||||
|
/// Does not initialize added items if any.
|
||||||
|
pub fn resize(self: *Self, len: usize) !void {
|
||||||
|
if (len > capacity) return error.Overflow;
|
||||||
|
self.len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy the content of an existing slice.
|
||||||
|
pub fn fromSlice(m: []const T) !Self {
|
||||||
|
var list = try init(m.len);
|
||||||
|
std.mem.copy(T, list.slice(), m);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the element at index `i` of the slice.
|
||||||
|
pub fn get(self: Self, i: usize) T {
|
||||||
|
return self.constSlice()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the value of the element at index `i` of the slice.
|
||||||
|
pub fn set(self: *Self, i: usize, item: T) void {
|
||||||
|
self.slice()[i] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum length of a slice.
|
||||||
|
pub fn capacity(self: Self) usize {
|
||||||
|
return self.buffer.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that the slice can hold at least `additional_count` items.
|
||||||
|
pub fn ensureUnusedCapacity(self: Self, additional_count: usize) !void {
|
||||||
|
if (self.len + additional_count > capacity) {
|
||||||
|
return error.Overflow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase length by 1, returning a pointer to the new item.
|
||||||
|
pub fn addOne(self: *Self) !*T {
|
||||||
|
try self.ensureUnusedCapacity(1);
|
||||||
|
return self.addOneAssumeCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase length by 1, returning pointer to the new item.
|
||||||
|
/// Asserts that there is space for the new item.
|
||||||
|
pub fn addOneAssumeCapacity(self: *Self) *T {
|
||||||
|
assert(self.len < capacity);
|
||||||
|
self.len += 1;
|
||||||
|
return &self.slice()[self.len - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resize the slice, adding `n` new elements, which have `undefined` values.
|
||||||
|
/// The return value is a slice pointing to the uninitialized elements.
|
||||||
|
pub fn addManyAsArray(self: *Self, comptime n: usize) !*[n]T {
|
||||||
|
const prev_len = self.len;
|
||||||
|
try self.resize(self.len + n);
|
||||||
|
return self.slice()[prev_len..][0..n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove and return the last element from the slice.
|
||||||
|
/// Asserts the slice has at least one item.
|
||||||
|
pub fn pop(self: *Self) T {
|
||||||
|
const item = self.get(self.len - 1);
|
||||||
|
self.len -= 1;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove and return the last element from the slice, or
|
||||||
|
/// return `null` if the slice is empty.
|
||||||
|
pub fn popOrNull(self: *Self) ?T {
|
||||||
|
return if (self.len == 0) null else self.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a slice of only the extra capacity after items.
|
||||||
|
/// This can be useful for writing directly into it.
|
||||||
|
/// Note that such an operation must be followed up with a
|
||||||
|
/// call to `resize()`
|
||||||
|
pub fn unusedCapacitySlice(self: *Self) []T {
|
||||||
|
return self.buffer[self.len..];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert `item` at index `i` by moving `slice[n .. slice.len]` to make room.
|
||||||
|
/// This operation is O(N).
|
||||||
|
pub fn insert(self: *Self, i: usize, item: T) !void {
|
||||||
|
if (i >= self.len) {
|
||||||
|
return error.IndexOutOfBounds;
|
||||||
|
}
|
||||||
|
_ = try self.addOne();
|
||||||
|
var s = self.slice();
|
||||||
|
mem.copyBackwards(T, s[i + 1 .. s.len], s[i .. s.len - 1]);
|
||||||
|
self.buffer[i] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert slice `items` at index `i` by moving `slice[i .. slice.len]` to make room.
|
||||||
|
/// This operation is O(N).
|
||||||
|
pub fn insertSlice(self: *Self, i: usize, items: []const T) !void {
|
||||||
|
try self.ensureUnusedCapacity(items.len);
|
||||||
|
self.len += items.len;
|
||||||
|
mem.copyBackwards(T, self.slice()[i + items.len .. self.len], self.constSlice()[i .. self.len - items.len]);
|
||||||
|
mem.copy(T, self.slice()[i .. i + items.len], items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace range of elements `slice[start..start+len]` with `new_items`.
|
||||||
|
/// Grows slice if `len < new_items.len`.
|
||||||
|
/// Shrinks slice if `len > new_items.len`.
|
||||||
|
pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) !void {
|
||||||
|
const after_range = start + len;
|
||||||
|
var range = self.slice()[start..after_range];
|
||||||
|
|
||||||
|
if (range.len == new_items.len) {
|
||||||
|
mem.copy(T, range, new_items);
|
||||||
|
} else if (range.len < new_items.len) {
|
||||||
|
const first = new_items[0..range.len];
|
||||||
|
const rest = new_items[range.len..];
|
||||||
|
mem.copy(T, range, first);
|
||||||
|
try self.insertSlice(after_range, rest);
|
||||||
|
} else {
|
||||||
|
mem.copy(T, range, new_items);
|
||||||
|
const after_subrange = start + new_items.len;
|
||||||
|
for (self.constSlice()[after_range..]) |item, i| {
|
||||||
|
self.slice()[after_subrange..][i] = item;
|
||||||
|
}
|
||||||
|
self.len -= len - new_items.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extend the slice by 1 element.
|
||||||
|
pub fn append(self: *Self, item: T) !void {
|
||||||
|
const new_item_ptr = try self.addOne();
|
||||||
|
new_item_ptr.* = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the element at index `i`, shift elements after index
|
||||||
|
/// `i` forward, and return the removed element.
|
||||||
|
/// Asserts the slice has at least one item.
|
||||||
|
/// This operation is O(N).
|
||||||
|
pub fn orderedRemove(self: *Self, i: usize) T {
|
||||||
|
const newlen = self.len - 1;
|
||||||
|
if (newlen == i) return self.pop();
|
||||||
|
const old_item = self.get(i);
|
||||||
|
for (self.slice()[i..newlen]) |*b, j| b.* = self.get(i + 1 + j);
|
||||||
|
self.set(newlen, undefined);
|
||||||
|
self.len = newlen;
|
||||||
|
return old_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the element at the specified index and return it.
|
||||||
|
/// The empty slot is filled from the end of the slice.
|
||||||
|
/// This operation is O(1).
|
||||||
|
pub fn swapRemove(self: *Self, i: usize) T {
|
||||||
|
if (self.len - 1 == i) return self.pop();
|
||||||
|
const old_item = self.get(i);
|
||||||
|
self.set(i, self.pop());
|
||||||
|
return old_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append the slice of items to the slice.
|
||||||
|
pub fn appendSlice(self: *Self, items: []const T) !void {
|
||||||
|
try self.ensureUnusedCapacity(items.len);
|
||||||
|
self.appendSliceAssumeCapacity(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append the slice of items to the slice, asserting the capacity is already
|
||||||
|
/// enough to store the new items.
|
||||||
|
pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
|
||||||
|
const oldlen = self.len;
|
||||||
|
self.len += items.len;
|
||||||
|
mem.copy(T, self.slice()[oldlen..], items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a value to the slice `n` times.
|
||||||
|
/// Allocates more memory as necessary.
|
||||||
|
pub fn appendNTimes(self: *Self, value: T, n: usize) !void {
|
||||||
|
const old_len = self.len;
|
||||||
|
try self.resize(old_len + n);
|
||||||
|
mem.set(T, self.slice()[old_len..self.len], value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a value to the slice `n` times.
|
||||||
|
/// Asserts the capacity is enough.
|
||||||
|
pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
|
||||||
|
const old_len = self.len;
|
||||||
|
self.len += n;
|
||||||
|
assert(self.len <= capacity);
|
||||||
|
mem.set(T, self.slice()[old_len..self.len], value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test "BoundedArray" {
|
||||||
|
var a = try BoundedArray(u8, 64).init(32);
|
||||||
|
|
||||||
|
try testing.expectEqual(a.capacity(), 64);
|
||||||
|
try testing.expectEqual(a.slice().len, 32);
|
||||||
|
try testing.expectEqual(a.constSlice().len, 32);
|
||||||
|
|
||||||
|
try a.resize(48);
|
||||||
|
try testing.expectEqual(a.len, 48);
|
||||||
|
|
||||||
|
const x = [_]u8{1} ** 10;
|
||||||
|
a = try BoundedArray(u8, 64).fromSlice(&x);
|
||||||
|
try testing.expectEqualSlices(u8, &x, a.constSlice());
|
||||||
|
|
||||||
|
var a2 = a;
|
||||||
|
try testing.expectEqualSlices(u8, a.constSlice(), a.constSlice());
|
||||||
|
a2.set(0, 0);
|
||||||
|
try testing.expect(a.get(0) != a2.get(0));
|
||||||
|
|
||||||
|
try testing.expectError(error.Overflow, a.resize(100));
|
||||||
|
try testing.expectError(error.Overflow, BoundedArray(u8, x.len - 1).fromSlice(&x));
|
||||||
|
|
||||||
|
try a.resize(0);
|
||||||
|
try a.ensureUnusedCapacity(a.capacity());
|
||||||
|
(try a.addOne()).* = 0;
|
||||||
|
try a.ensureUnusedCapacity(a.capacity() - 1);
|
||||||
|
try testing.expectEqual(a.len, 1);
|
||||||
|
|
||||||
|
const uninitialized = try a.addManyAsArray(4);
|
||||||
|
try testing.expectEqual(uninitialized.len, 4);
|
||||||
|
try testing.expectEqual(a.len, 5);
|
||||||
|
|
||||||
|
try a.append(0xff);
|
||||||
|
try testing.expectEqual(a.len, 6);
|
||||||
|
try testing.expectEqual(a.pop(), 0xff);
|
||||||
|
|
||||||
|
try a.resize(1);
|
||||||
|
try testing.expectEqual(a.popOrNull(), 0);
|
||||||
|
try testing.expectEqual(a.popOrNull(), null);
|
||||||
|
var unused = a.unusedCapacitySlice();
|
||||||
|
mem.set(u8, unused[0..8], 2);
|
||||||
|
unused[8] = 3;
|
||||||
|
unused[9] = 4;
|
||||||
|
try testing.expectEqual(unused.len, a.capacity());
|
||||||
|
try a.resize(10);
|
||||||
|
|
||||||
|
try a.insert(5, 0xaa);
|
||||||
|
try testing.expectEqual(a.len, 11);
|
||||||
|
try testing.expectEqual(a.get(5), 0xaa);
|
||||||
|
try testing.expectEqual(a.get(9), 3);
|
||||||
|
try testing.expectEqual(a.get(10), 4);
|
||||||
|
|
||||||
|
try a.appendSlice(&x);
|
||||||
|
try testing.expectEqual(a.len, 11 + x.len);
|
||||||
|
|
||||||
|
try a.appendNTimes(0xbb, 5);
|
||||||
|
try testing.expectEqual(a.len, 11 + x.len + 5);
|
||||||
|
try testing.expectEqual(a.pop(), 0xbb);
|
||||||
|
|
||||||
|
a.appendNTimesAssumeCapacity(0xcc, 5);
|
||||||
|
try testing.expectEqual(a.len, 11 + x.len + 5 - 1 + 5);
|
||||||
|
try testing.expectEqual(a.pop(), 0xcc);
|
||||||
|
|
||||||
|
try testing.expectEqual(a.len, 29);
|
||||||
|
try a.replaceRange(1, 20, &x);
|
||||||
|
try testing.expectEqual(a.len, 29 + x.len - 20);
|
||||||
|
|
||||||
|
try a.insertSlice(0, &x);
|
||||||
|
try testing.expectEqual(a.len, 29 + x.len - 20 + x.len);
|
||||||
|
|
||||||
|
try a.replaceRange(1, 5, &x);
|
||||||
|
try testing.expectEqual(a.len, 29 + x.len - 20 + x.len + x.len - 5);
|
||||||
|
|
||||||
|
try a.append(10);
|
||||||
|
try testing.expectEqual(a.pop(), 10);
|
||||||
|
|
||||||
|
try a.append(20);
|
||||||
|
const removed = a.orderedRemove(5);
|
||||||
|
try testing.expectEqual(removed, 1);
|
||||||
|
try testing.expectEqual(a.len, 34);
|
||||||
|
|
||||||
|
a.set(0, 0xdd);
|
||||||
|
a.set(a.len - 1, 0xee);
|
||||||
|
const swapped = a.swapRemove(0);
|
||||||
|
try testing.expectEqual(swapped, 0xdd);
|
||||||
|
try testing.expectEqual(a.get(0), 0xee);
|
||||||
|
}
|
||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const StringHashMap = std.StringHashMap;
|
const StringHashMap = std.StringHashMap;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const StringHashMap = std.StringHashMap;
|
const StringHashMap = std.StringHashMap;
|
||||||
const mem = @import("mem.zig");
|
const mem = @import("mem.zig");
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
@ -28,6 +23,7 @@ pub const WriteFileStep = @import("build/WriteFileStep.zig");
|
|||||||
pub const RunStep = @import("build/RunStep.zig");
|
pub const RunStep = @import("build/RunStep.zig");
|
||||||
pub const CheckFileStep = @import("build/CheckFileStep.zig");
|
pub const CheckFileStep = @import("build/CheckFileStep.zig");
|
||||||
pub const InstallRawStep = @import("build/InstallRawStep.zig");
|
pub const InstallRawStep = @import("build/InstallRawStep.zig");
|
||||||
|
pub const OptionsStep = @import("build/OptionsStep.zig");
|
||||||
|
|
||||||
pub const Builder = struct {
|
pub const Builder = struct {
|
||||||
install_tls: TopLevelStep,
|
install_tls: TopLevelStep,
|
||||||
@ -252,6 +248,10 @@ pub const Builder = struct {
|
|||||||
return LibExeObjStep.createExecutable(builder, name, root_src);
|
return LibExeObjStep.createExecutable(builder, name, root_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addOptions(self: *Builder) *OptionsStep {
|
||||||
|
return OptionsStep.create(self);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||||
return addObjectSource(self, name, convertOptionalPathToFileSource(root_src));
|
return addObjectSource(self, name, convertOptionalPathToFileSource(root_src));
|
||||||
}
|
}
|
||||||
@ -1380,16 +1380,6 @@ pub const FileSource = union(enum) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const BuildOptionArtifactArg = struct {
|
|
||||||
name: []const u8,
|
|
||||||
artifact: *LibExeObjStep,
|
|
||||||
};
|
|
||||||
|
|
||||||
const BuildOptionFileSourceArg = struct {
|
|
||||||
name: []const u8,
|
|
||||||
source: FileSource,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const LibExeObjStep = struct {
|
pub const LibExeObjStep = struct {
|
||||||
pub const base_id = .lib_exe_obj;
|
pub const base_id = .lib_exe_obj;
|
||||||
|
|
||||||
@ -1432,15 +1422,13 @@ pub const LibExeObjStep = struct {
|
|||||||
single_threaded: bool,
|
single_threaded: bool,
|
||||||
test_evented_io: bool = false,
|
test_evented_io: bool = false,
|
||||||
code_model: builtin.CodeModel = .default,
|
code_model: builtin.CodeModel = .default,
|
||||||
|
wasi_exec_model: ?builtin.WasiExecModel = null,
|
||||||
|
|
||||||
root_src: ?FileSource,
|
root_src: ?FileSource,
|
||||||
out_h_filename: []const u8,
|
out_h_filename: []const u8,
|
||||||
out_lib_filename: []const u8,
|
out_lib_filename: []const u8,
|
||||||
out_pdb_filename: []const u8,
|
out_pdb_filename: []const u8,
|
||||||
packages: ArrayList(Pkg),
|
packages: ArrayList(Pkg),
|
||||||
build_options_contents: std.ArrayList(u8),
|
|
||||||
build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg),
|
|
||||||
build_options_file_source_args: std.ArrayList(BuildOptionFileSourceArg),
|
|
||||||
|
|
||||||
object_src: []const u8,
|
object_src: []const u8,
|
||||||
|
|
||||||
@ -1607,9 +1595,6 @@ pub const LibExeObjStep = struct {
|
|||||||
.rpaths = ArrayList([]const u8).init(builder.allocator),
|
.rpaths = ArrayList([]const u8).init(builder.allocator),
|
||||||
.framework_dirs = ArrayList([]const u8).init(builder.allocator),
|
.framework_dirs = ArrayList([]const u8).init(builder.allocator),
|
||||||
.object_src = undefined,
|
.object_src = undefined,
|
||||||
.build_options_contents = std.ArrayList(u8).init(builder.allocator),
|
|
||||||
.build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator),
|
|
||||||
.build_options_file_source_args = std.ArrayList(BuildOptionFileSourceArg).init(builder.allocator),
|
|
||||||
.c_std = Builder.CStd.C99,
|
.c_std = Builder.CStd.C99,
|
||||||
.override_lib_dir = null,
|
.override_lib_dir = null,
|
||||||
.main_pkg_path = null,
|
.main_pkg_path = null,
|
||||||
@ -1735,7 +1720,6 @@ pub const LibExeObjStep = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void {
|
pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void {
|
||||||
assert(self.target.isDarwin());
|
|
||||||
// Note: No need to dupe because frameworks dupes internally.
|
// Note: No need to dupe because frameworks dupes internally.
|
||||||
self.frameworks.insert(framework_name) catch unreachable;
|
self.frameworks.insert(framework_name) catch unreachable;
|
||||||
}
|
}
|
||||||
@ -2043,119 +2027,6 @@ pub const LibExeObjStep = struct {
|
|||||||
self.linkLibraryOrObject(obj);
|
self.linkLibraryOrObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {
|
|
||||||
const out = self.build_options_contents.writer();
|
|
||||||
switch (T) {
|
|
||||||
[]const []const u8 => {
|
|
||||||
out.print("pub const {}: []const []const u8 = &[_][]const u8{{\n", .{std.zig.fmtId(name)}) catch unreachable;
|
|
||||||
for (value) |slice| {
|
|
||||||
out.print(" \"{}\",\n", .{std.zig.fmtEscapes(slice)}) catch unreachable;
|
|
||||||
}
|
|
||||||
out.writeAll("};\n") catch unreachable;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
[:0]const u8 => {
|
|
||||||
out.print("pub const {}: [:0]const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
[]const u8 => {
|
|
||||||
out.print("pub const {}: []const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
?[:0]const u8 => {
|
|
||||||
out.print("pub const {}: ?[:0]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;
|
|
||||||
if (value) |payload| {
|
|
||||||
out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}) catch unreachable;
|
|
||||||
} else {
|
|
||||||
out.writeAll("null;\n") catch unreachable;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
?[]const u8 => {
|
|
||||||
out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;
|
|
||||||
if (value) |payload| {
|
|
||||||
out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}) catch unreachable;
|
|
||||||
} else {
|
|
||||||
out.writeAll("null;\n") catch unreachable;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
std.builtin.Version => {
|
|
||||||
out.print(
|
|
||||||
\\pub const {}: @import("std").builtin.Version = .{{
|
|
||||||
\\ .major = {d},
|
|
||||||
\\ .minor = {d},
|
|
||||||
\\ .patch = {d},
|
|
||||||
\\}};
|
|
||||||
\\
|
|
||||||
, .{
|
|
||||||
std.zig.fmtId(name),
|
|
||||||
|
|
||||||
value.major,
|
|
||||||
value.minor,
|
|
||||||
value.patch,
|
|
||||||
}) catch unreachable;
|
|
||||||
},
|
|
||||||
std.SemanticVersion => {
|
|
||||||
out.print(
|
|
||||||
\\pub const {}: @import("std").SemanticVersion = .{{
|
|
||||||
\\ .major = {d},
|
|
||||||
\\ .minor = {d},
|
|
||||||
\\ .patch = {d},
|
|
||||||
\\
|
|
||||||
, .{
|
|
||||||
std.zig.fmtId(name),
|
|
||||||
|
|
||||||
value.major,
|
|
||||||
value.minor,
|
|
||||||
value.patch,
|
|
||||||
}) catch unreachable;
|
|
||||||
if (value.pre) |some| {
|
|
||||||
out.print(" .pre = \"{}\",\n", .{std.zig.fmtEscapes(some)}) catch unreachable;
|
|
||||||
}
|
|
||||||
if (value.build) |some| {
|
|
||||||
out.print(" .build = \"{}\",\n", .{std.zig.fmtEscapes(some)}) catch unreachable;
|
|
||||||
}
|
|
||||||
out.writeAll("};\n") catch unreachable;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
switch (@typeInfo(T)) {
|
|
||||||
.Enum => |enum_info| {
|
|
||||||
out.print("pub const {} = enum {{\n", .{std.zig.fmtId(@typeName(T))}) catch unreachable;
|
|
||||||
inline for (enum_info.fields) |field| {
|
|
||||||
out.print(" {},\n", .{std.zig.fmtId(field.name)}) catch unreachable;
|
|
||||||
}
|
|
||||||
out.writeAll("};\n") catch unreachable;
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
out.print("pub const {}: {s} = {};\n", .{ std.zig.fmtId(name), @typeName(T), value }) catch unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The value is the path in the cache dir.
|
|
||||||
/// Adds a dependency automatically.
|
|
||||||
pub fn addBuildOptionArtifact(self: *LibExeObjStep, name: []const u8, artifact: *LibExeObjStep) void {
|
|
||||||
self.build_options_artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch unreachable;
|
|
||||||
self.step.dependOn(&artifact.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The value is the path in the cache dir.
|
|
||||||
/// Adds a dependency automatically.
|
|
||||||
/// basename refers to the basename of the WriteFileStep
|
|
||||||
pub fn addBuildOptionFileSource(
|
|
||||||
self: *LibExeObjStep,
|
|
||||||
name: []const u8,
|
|
||||||
source: FileSource,
|
|
||||||
) void {
|
|
||||||
self.build_options_file_source_args.append(.{
|
|
||||||
.name = name,
|
|
||||||
.source = source.dupe(self.builder),
|
|
||||||
}) catch unreachable;
|
|
||||||
source.addStepDependencies(&self.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {
|
pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {
|
||||||
self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable;
|
self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable;
|
||||||
}
|
}
|
||||||
@ -2181,6 +2052,10 @@ pub const LibExeObjStep = struct {
|
|||||||
self.addRecursiveBuildDeps(package);
|
self.addRecursiveBuildDeps(package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addOptions(self: *LibExeObjStep, package_name: []const u8, options: *OptionsStep) void {
|
||||||
|
self.addPackage(options.getPackage(package_name));
|
||||||
|
}
|
||||||
|
|
||||||
fn addRecursiveBuildDeps(self: *LibExeObjStep, package: Pkg) void {
|
fn addRecursiveBuildDeps(self: *LibExeObjStep, package: Pkg) void {
|
||||||
package.path.addStepDependencies(&self.step);
|
package.path.addStepDependencies(&self.step);
|
||||||
if (package.dependencies) |deps| {
|
if (package.dependencies) |deps| {
|
||||||
@ -2247,28 +2122,6 @@ pub const LibExeObjStep = struct {
|
|||||||
self.step.dependOn(&other.step);
|
self.step.dependOn(&other.step);
|
||||||
self.link_objects.append(.{ .other_step = other }) catch unreachable;
|
self.link_objects.append(.{ .other_step = other }) catch unreachable;
|
||||||
self.include_dirs.append(.{ .other_step = other }) catch unreachable;
|
self.include_dirs.append(.{ .other_step = other }) catch unreachable;
|
||||||
|
|
||||||
// BUG: The following code introduces a order-of-call dependency:
|
|
||||||
// var lib = addSharedLibrary(...);
|
|
||||||
// var exe = addExecutable(...);
|
|
||||||
// exe.linkLibrary(lib);
|
|
||||||
// lib.linkSystemLibrary("foobar"); // this will be ignored for exe!
|
|
||||||
|
|
||||||
// Inherit dependency on system libraries
|
|
||||||
for (other.link_objects.items) |link_object| {
|
|
||||||
switch (link_object) {
|
|
||||||
.system_lib => |name| self.linkSystemLibrary(name),
|
|
||||||
else => continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inherit dependencies on darwin frameworks
|
|
||||||
if (self.target.isDarwin() and !other.isDynamicLibrary()) {
|
|
||||||
var it = other.frameworks.iterator();
|
|
||||||
while (it.next()) |framework| {
|
|
||||||
self.frameworks.insert(framework.*) catch unreachable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn makePackageCmd(self: *LibExeObjStep, pkg: Pkg, zig_args: *ArrayList([]const u8)) error{OutOfMemory}!void {
|
fn makePackageCmd(self: *LibExeObjStep, pkg: Pkg, zig_args: *ArrayList([]const u8)) error{OutOfMemory}!void {
|
||||||
@ -2322,6 +2175,31 @@ pub const LibExeObjStep = struct {
|
|||||||
if (self.root_src) |root_src| try zig_args.append(root_src.getPath(builder));
|
if (self.root_src) |root_src| try zig_args.append(root_src.getPath(builder));
|
||||||
|
|
||||||
var prev_has_extra_flags = false;
|
var prev_has_extra_flags = false;
|
||||||
|
|
||||||
|
// Resolve transitive dependencies
|
||||||
|
for (self.link_objects.items) |link_object| {
|
||||||
|
switch (link_object) {
|
||||||
|
.other_step => |other| {
|
||||||
|
// Inherit dependency on system libraries
|
||||||
|
for (other.link_objects.items) |other_link_object| {
|
||||||
|
switch (other_link_object) {
|
||||||
|
.system_lib => |name| self.linkSystemLibrary(name),
|
||||||
|
else => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherit dependencies on darwin frameworks
|
||||||
|
if (!other.isDynamicLibrary()) {
|
||||||
|
var it = other.frameworks.iterator();
|
||||||
|
while (it.next()) |framework| {
|
||||||
|
self.frameworks.insert(framework.*) catch unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (self.link_objects.items) |link_object| {
|
for (self.link_objects.items) |link_object| {
|
||||||
switch (link_object) {
|
switch (link_object) {
|
||||||
.static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
|
.static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
|
||||||
@ -2395,41 +2273,6 @@ pub const LibExeObjStep = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.build_options_contents.items.len > 0 or
|
|
||||||
self.build_options_artifact_args.items.len > 0 or
|
|
||||||
self.build_options_file_source_args.items.len > 0)
|
|
||||||
{
|
|
||||||
// Render build artifact and write file options at the last minute, now that the path is known.
|
|
||||||
//
|
|
||||||
// Note that pathFromRoot uses resolve path, so this will have
|
|
||||||
// correct behavior even if getOutputPath is already absolute.
|
|
||||||
for (self.build_options_artifact_args.items) |item| {
|
|
||||||
self.addBuildOption(
|
|
||||||
[]const u8,
|
|
||||||
item.name,
|
|
||||||
self.builder.pathFromRoot(item.artifact.getOutputSource().getPath(self.builder)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for (self.build_options_file_source_args.items) |item| {
|
|
||||||
self.addBuildOption(
|
|
||||||
[]const u8,
|
|
||||||
item.name,
|
|
||||||
item.source.getPath(self.builder),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const build_options_file = try fs.path.join(
|
|
||||||
builder.allocator,
|
|
||||||
&[_][]const u8{ builder.cache_root, builder.fmt("{s}_build_options.zig", .{self.name}) },
|
|
||||||
);
|
|
||||||
const path_from_root = builder.pathFromRoot(build_options_file);
|
|
||||||
try fs.cwd().writeFile(path_from_root, self.build_options_contents.items);
|
|
||||||
try zig_args.append("--pkg-begin");
|
|
||||||
try zig_args.append("build_options");
|
|
||||||
try zig_args.append(path_from_root);
|
|
||||||
try zig_args.append("--pkg-end");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.image_base) |image_base| {
|
if (self.image_base) |image_base| {
|
||||||
try zig_args.append("--image-base");
|
try zig_args.append("--image-base");
|
||||||
try zig_args.append(builder.fmt("0x{x}", .{image_base}));
|
try zig_args.append(builder.fmt("0x{x}", .{image_base}));
|
||||||
@ -2547,6 +2390,9 @@ pub const LibExeObjStep = struct {
|
|||||||
try zig_args.append("-mcmodel");
|
try zig_args.append("-mcmodel");
|
||||||
try zig_args.append(@tagName(self.code_model));
|
try zig_args.append(@tagName(self.code_model));
|
||||||
}
|
}
|
||||||
|
if (self.wasi_exec_model) |model| {
|
||||||
|
try zig_args.append(builder.fmt("-mexec-model={s}", .{@tagName(model)}));
|
||||||
|
}
|
||||||
|
|
||||||
if (!self.target.isNative()) {
|
if (!self.target.isNative()) {
|
||||||
try zig_args.append("-target");
|
try zig_args.append("-target");
|
||||||
@ -2719,6 +2565,14 @@ pub const LibExeObjStep = struct {
|
|||||||
zig_args.append("-framework") catch unreachable;
|
zig_args.append("-framework") catch unreachable;
|
||||||
zig_args.append(framework.*) catch unreachable;
|
zig_args.append(framework.*) catch unreachable;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (self.framework_dirs.items.len > 0) {
|
||||||
|
warn("Framework directories have been added for a non-darwin target, this will have no affect on the build\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.frameworks.count() > 0) {
|
||||||
|
warn("Frameworks have been added for a non-darwin target, this will have no affect on the build\n", .{});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builder.sysroot) |sysroot| {
|
if (builder.sysroot) |sysroot| {
|
||||||
@ -3026,7 +2880,8 @@ pub const InstallDirStep = struct {
|
|||||||
const self = @fieldParentPtr(InstallDirStep, "step", step);
|
const self = @fieldParentPtr(InstallDirStep, "step", step);
|
||||||
const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
|
const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
|
||||||
const full_src_dir = self.builder.pathFromRoot(self.options.source_dir);
|
const full_src_dir = self.builder.pathFromRoot(self.options.source_dir);
|
||||||
const src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true });
|
var src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true });
|
||||||
|
defer src_dir.close();
|
||||||
var it = try src_dir.walk(self.builder.allocator);
|
var it = try src_dir.walk(self.builder.allocator);
|
||||||
next_entry: while (try it.next()) |entry| {
|
next_entry: while (try it.next()) |entry| {
|
||||||
for (self.options.exclude_extensions) |ext| {
|
for (self.options.exclude_extensions) |ext| {
|
||||||
@ -3131,6 +2986,7 @@ pub const Step = struct {
|
|||||||
run,
|
run,
|
||||||
check_file,
|
check_file,
|
||||||
install_raw,
|
install_raw,
|
||||||
|
options,
|
||||||
custom,
|
custom,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3302,43 +3158,6 @@ test "Builder.dupePkg()" {
|
|||||||
try std.testing.expect(dupe_deps[0].path.path.ptr != pkg_dep.path.path.ptr);
|
try std.testing.expect(dupe_deps[0].path.path.ptr != pkg_dep.path.path.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "LibExeObjStep.addBuildOption" {
|
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
|
||||||
|
|
||||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
|
||||||
defer arena.deinit();
|
|
||||||
var builder = try Builder.create(
|
|
||||||
&arena.allocator,
|
|
||||||
"test",
|
|
||||||
"test",
|
|
||||||
"test",
|
|
||||||
"test",
|
|
||||||
);
|
|
||||||
defer builder.destroy();
|
|
||||||
|
|
||||||
var exe = builder.addExecutable("not_an_executable", "/not/an/executable.zig");
|
|
||||||
exe.addBuildOption(usize, "option1", 1);
|
|
||||||
exe.addBuildOption(?usize, "option2", null);
|
|
||||||
exe.addBuildOption([]const u8, "string", "zigisthebest");
|
|
||||||
exe.addBuildOption(?[]const u8, "optional_string", null);
|
|
||||||
exe.addBuildOption(std.SemanticVersion, "semantic_version", try std.SemanticVersion.parse("0.1.2-foo+bar"));
|
|
||||||
|
|
||||||
try std.testing.expectEqualStrings(
|
|
||||||
\\pub const option1: usize = 1;
|
|
||||||
\\pub const option2: ?usize = null;
|
|
||||||
\\pub const string: []const u8 = "zigisthebest";
|
|
||||||
\\pub const optional_string: ?[]const u8 = null;
|
|
||||||
\\pub const semantic_version: @import("std").SemanticVersion = .{
|
|
||||||
\\ .major = 0,
|
|
||||||
\\ .minor = 1,
|
|
||||||
\\ .patch = 2,
|
|
||||||
\\ .pre = "foo",
|
|
||||||
\\ .build = "bar",
|
|
||||||
\\};
|
|
||||||
\\
|
|
||||||
, exe.build_options_contents.items);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "LibExeObjStep.addPackage" {
|
test "LibExeObjStep.addPackage" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const build = std.build;
|
const build = std.build;
|
||||||
const Step = build.Step;
|
const Step = build.Step;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const build = @import("../build.zig");
|
const build = @import("../build.zig");
|
||||||
const Step = build.Step;
|
const Step = build.Step;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|||||||
257
lib/std/build/OptionsStep.zig
Normal file
257
lib/std/build/OptionsStep.zig
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
const std = @import("../std.zig");
|
||||||
|
const build = std.build;
|
||||||
|
const fs = std.fs;
|
||||||
|
const Step = build.Step;
|
||||||
|
const Builder = build.Builder;
|
||||||
|
const GeneratedFile = build.GeneratedFile;
|
||||||
|
const LibExeObjStep = build.LibExeObjStep;
|
||||||
|
const FileSource = build.FileSource;
|
||||||
|
|
||||||
|
const OptionsStep = @This();
|
||||||
|
|
||||||
|
step: Step,
|
||||||
|
generated_file: GeneratedFile,
|
||||||
|
builder: *Builder,
|
||||||
|
|
||||||
|
contents: std.ArrayList(u8),
|
||||||
|
artifact_args: std.ArrayList(OptionArtifactArg),
|
||||||
|
file_source_args: std.ArrayList(OptionFileSourceArg),
|
||||||
|
|
||||||
|
pub fn create(builder: *Builder) *OptionsStep {
|
||||||
|
const self = builder.allocator.create(OptionsStep) catch unreachable;
|
||||||
|
self.* = .{
|
||||||
|
.builder = builder,
|
||||||
|
.step = Step.init(.options, "options", builder.allocator, make),
|
||||||
|
.generated_file = undefined,
|
||||||
|
.contents = std.ArrayList(u8).init(builder.allocator),
|
||||||
|
.artifact_args = std.ArrayList(OptionArtifactArg).init(builder.allocator),
|
||||||
|
.file_source_args = std.ArrayList(OptionFileSourceArg).init(builder.allocator),
|
||||||
|
};
|
||||||
|
self.generated_file = .{ .step = &self.step };
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addOption(self: *OptionsStep, comptime T: type, name: []const u8, value: T) void {
|
||||||
|
const out = self.contents.writer();
|
||||||
|
switch (T) {
|
||||||
|
[]const []const u8 => {
|
||||||
|
out.print("pub const {}: []const []const u8 = &[_][]const u8{{\n", .{std.zig.fmtId(name)}) catch unreachable;
|
||||||
|
for (value) |slice| {
|
||||||
|
out.print(" \"{}\",\n", .{std.zig.fmtEscapes(slice)}) catch unreachable;
|
||||||
|
}
|
||||||
|
out.writeAll("};\n") catch unreachable;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
[:0]const u8 => {
|
||||||
|
out.print("pub const {}: [:0]const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
[]const u8 => {
|
||||||
|
out.print("pub const {}: []const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
?[:0]const u8 => {
|
||||||
|
out.print("pub const {}: ?[:0]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;
|
||||||
|
if (value) |payload| {
|
||||||
|
out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}) catch unreachable;
|
||||||
|
} else {
|
||||||
|
out.writeAll("null;\n") catch unreachable;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
?[]const u8 => {
|
||||||
|
out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;
|
||||||
|
if (value) |payload| {
|
||||||
|
out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}) catch unreachable;
|
||||||
|
} else {
|
||||||
|
out.writeAll("null;\n") catch unreachable;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
std.builtin.Version => {
|
||||||
|
out.print(
|
||||||
|
\\pub const {}: @import("std").builtin.Version = .{{
|
||||||
|
\\ .major = {d},
|
||||||
|
\\ .minor = {d},
|
||||||
|
\\ .patch = {d},
|
||||||
|
\\}};
|
||||||
|
\\
|
||||||
|
, .{
|
||||||
|
std.zig.fmtId(name),
|
||||||
|
|
||||||
|
value.major,
|
||||||
|
value.minor,
|
||||||
|
value.patch,
|
||||||
|
}) catch unreachable;
|
||||||
|
},
|
||||||
|
std.SemanticVersion => {
|
||||||
|
out.print(
|
||||||
|
\\pub const {}: @import("std").SemanticVersion = .{{
|
||||||
|
\\ .major = {d},
|
||||||
|
\\ .minor = {d},
|
||||||
|
\\ .patch = {d},
|
||||||
|
\\
|
||||||
|
, .{
|
||||||
|
std.zig.fmtId(name),
|
||||||
|
|
||||||
|
value.major,
|
||||||
|
value.minor,
|
||||||
|
value.patch,
|
||||||
|
}) catch unreachable;
|
||||||
|
if (value.pre) |some| {
|
||||||
|
out.print(" .pre = \"{}\",\n", .{std.zig.fmtEscapes(some)}) catch unreachable;
|
||||||
|
}
|
||||||
|
if (value.build) |some| {
|
||||||
|
out.print(" .build = \"{}\",\n", .{std.zig.fmtEscapes(some)}) catch unreachable;
|
||||||
|
}
|
||||||
|
out.writeAll("};\n") catch unreachable;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
switch (@typeInfo(T)) {
|
||||||
|
.Enum => |enum_info| {
|
||||||
|
out.print("pub const {} = enum {{\n", .{std.zig.fmtId(@typeName(T))}) catch unreachable;
|
||||||
|
inline for (enum_info.fields) |field| {
|
||||||
|
out.print(" {},\n", .{std.zig.fmtId(field.name)}) catch unreachable;
|
||||||
|
}
|
||||||
|
out.writeAll("};\n") catch unreachable;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
out.print("pub const {}: {s} = {};\n", .{ std.zig.fmtId(name), @typeName(T), value }) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value is the path in the cache dir.
|
||||||
|
/// Adds a dependency automatically.
|
||||||
|
pub fn addOptionFileSource(
|
||||||
|
self: *OptionsStep,
|
||||||
|
name: []const u8,
|
||||||
|
source: FileSource,
|
||||||
|
) void {
|
||||||
|
self.file_source_args.append(.{
|
||||||
|
.name = name,
|
||||||
|
.source = source.dupe(self.builder),
|
||||||
|
}) catch unreachable;
|
||||||
|
source.addStepDependencies(&self.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value is the path in the cache dir.
|
||||||
|
/// Adds a dependency automatically.
|
||||||
|
pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *LibExeObjStep) void {
|
||||||
|
self.artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch unreachable;
|
||||||
|
self.step.dependOn(&artifact.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getPackage(self: OptionsStep, package_name: []const u8) build.Pkg {
|
||||||
|
return .{ .name = package_name, .path = self.getSource() };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getSource(self: OptionsStep) FileSource {
|
||||||
|
return .{ .generated = &self.generated_file };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make(step: *Step) !void {
|
||||||
|
const self = @fieldParentPtr(OptionsStep, "step", step);
|
||||||
|
|
||||||
|
for (self.artifact_args.items) |item| {
|
||||||
|
self.addOption(
|
||||||
|
[]const u8,
|
||||||
|
item.name,
|
||||||
|
self.builder.pathFromRoot(item.artifact.getOutputSource().getPath(self.builder)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.file_source_args.items) |item| {
|
||||||
|
self.addOption(
|
||||||
|
[]const u8,
|
||||||
|
item.name,
|
||||||
|
item.source.getPath(self.builder),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const options_directory = self.builder.pathFromRoot(
|
||||||
|
try fs.path.join(
|
||||||
|
self.builder.allocator,
|
||||||
|
&[_][]const u8{ self.builder.cache_root, "options" },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
try fs.cwd().makePath(options_directory);
|
||||||
|
|
||||||
|
const options_file = try fs.path.join(
|
||||||
|
self.builder.allocator,
|
||||||
|
&[_][]const u8{ options_directory, &self.hashContentsToFileName() },
|
||||||
|
);
|
||||||
|
|
||||||
|
try fs.cwd().writeFile(options_file, self.contents.items);
|
||||||
|
|
||||||
|
self.generated_file.path = options_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hashContentsToFileName(self: *OptionsStep) [64]u8 {
|
||||||
|
// This implementation is copied from `WriteFileStep.make`
|
||||||
|
|
||||||
|
var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
|
||||||
|
|
||||||
|
// Random bytes to make OptionsStep unique. Refresh this with
|
||||||
|
// new random bytes when OptionsStep implementation is modified
|
||||||
|
// in a non-backwards-compatible way.
|
||||||
|
hash.update("yL0Ya4KkmcCjBlP8");
|
||||||
|
hash.update(self.contents.items);
|
||||||
|
|
||||||
|
var digest: [48]u8 = undefined;
|
||||||
|
hash.final(&digest);
|
||||||
|
var hash_basename: [64]u8 = undefined;
|
||||||
|
_ = fs.base64_encoder.encode(&hash_basename, &digest);
|
||||||
|
return hash_basename;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OptionArtifactArg = struct {
|
||||||
|
name: []const u8,
|
||||||
|
artifact: *LibExeObjStep,
|
||||||
|
};
|
||||||
|
|
||||||
|
const OptionFileSourceArg = struct {
|
||||||
|
name: []const u8,
|
||||||
|
source: FileSource,
|
||||||
|
};
|
||||||
|
|
||||||
|
test "OptionsStep" {
|
||||||
|
if (std.builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
|
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
var builder = try Builder.create(
|
||||||
|
&arena.allocator,
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
);
|
||||||
|
defer builder.destroy();
|
||||||
|
|
||||||
|
const options = builder.addOptions();
|
||||||
|
|
||||||
|
options.addOption(usize, "option1", 1);
|
||||||
|
options.addOption(?usize, "option2", null);
|
||||||
|
options.addOption([]const u8, "string", "zigisthebest");
|
||||||
|
options.addOption(?[]const u8, "optional_string", null);
|
||||||
|
options.addOption(std.SemanticVersion, "semantic_version", try std.SemanticVersion.parse("0.1.2-foo+bar"));
|
||||||
|
|
||||||
|
try std.testing.expectEqualStrings(
|
||||||
|
\\pub const option1: usize = 1;
|
||||||
|
\\pub const option2: ?usize = null;
|
||||||
|
\\pub const string: []const u8 = "zigisthebest";
|
||||||
|
\\pub const optional_string: ?[]const u8 = null;
|
||||||
|
\\pub const semantic_version: @import("std").SemanticVersion = .{
|
||||||
|
\\ .major = 0,
|
||||||
|
\\ .minor = 1,
|
||||||
|
\\ .patch = 2,
|
||||||
|
\\ .pre = "foo",
|
||||||
|
\\ .build = "bar",
|
||||||
|
\\};
|
||||||
|
\\
|
||||||
|
, options.contents.items);
|
||||||
|
}
|
||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const build = std.build;
|
const build = std.build;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const build = std.build;
|
const build = std.build;
|
||||||
const Step = build.Step;
|
const Step = build.Step;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const build = @import("../build.zig");
|
const build = @import("../build.zig");
|
||||||
const Step = build.Step;
|
const Step = build.Step;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
// These are all deprecated.
|
// These are all deprecated.
|
||||||
@ -237,7 +232,7 @@ pub const TypeInfo = union(enum) {
|
|||||||
/// This field is an optional type.
|
/// This field is an optional type.
|
||||||
/// The type of the sentinel is the element type of the pointer, which is
|
/// The type of the sentinel is the element type of the pointer, which is
|
||||||
/// the value of the `child` field in this struct. However there is no way
|
/// the value of the `child` field in this struct. However there is no way
|
||||||
/// to refer to that type here, so we use `var`.
|
/// to refer to that type here, so we use `anytype`.
|
||||||
sentinel: anytype,
|
sentinel: anytype,
|
||||||
|
|
||||||
/// This data structure is used by the Zig language code generation and
|
/// This data structure is used by the Zig language code generation and
|
||||||
@ -259,7 +254,7 @@ pub const TypeInfo = union(enum) {
|
|||||||
/// This field is an optional type.
|
/// This field is an optional type.
|
||||||
/// The type of the sentinel is the element type of the array, which is
|
/// The type of the sentinel is the element type of the array, which is
|
||||||
/// the value of the `child` field in this struct. However there is no way
|
/// the value of the `child` field in this struct. However there is no way
|
||||||
/// to refer to that type here, so we use `var`.
|
/// to refer to that type here, so we use `anytype`.
|
||||||
sentinel: anytype,
|
sentinel: anytype,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -671,7 +666,12 @@ pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;
|
|||||||
|
|
||||||
/// This function is used by the Zig language code generation and
|
/// This function is used by the Zig language code generation and
|
||||||
/// therefore must be kept in sync with the compiler implementation.
|
/// therefore must be kept in sync with the compiler implementation.
|
||||||
pub const panic: PanicFn = if (@hasDecl(root, "panic")) root.panic else default_panic;
|
pub const panic: PanicFn = if (@hasDecl(root, "panic"))
|
||||||
|
root.panic
|
||||||
|
else if (@hasDecl(root, "os") and @hasDecl(root.os, "panic"))
|
||||||
|
root.os.panic
|
||||||
|
else
|
||||||
|
default_panic;
|
||||||
|
|
||||||
/// This function is used by the Zig language code generation and
|
/// This function is used by the Zig language code generation and
|
||||||
/// therefore must be kept in sync with the compiler implementation.
|
/// therefore must be kept in sync with the compiler implementation.
|
||||||
@ -684,10 +684,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
|
|||||||
@breakpoint();
|
@breakpoint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (@hasDecl(root, "os") and @hasDecl(root.os, "panic")) {
|
|
||||||
root.os.panic(msg, error_return_trace);
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
switch (os.tag) {
|
switch (os.tag) {
|
||||||
.freestanding => {
|
.freestanding => {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const page_size = std.mem.page_size;
|
const page_size = std.mem.page_size;
|
||||||
@ -35,11 +30,11 @@ pub usingnamespace switch (std.Target.current.os.tag) {
|
|||||||
else => struct {},
|
else => struct {},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getErrno(rc: anytype) c_int {
|
pub fn getErrno(rc: anytype) E {
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return _errno().*;
|
return @intToEnum(E, _errno().*);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return .SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,22 +265,22 @@ pub extern "c" fn utimes(path: [*:0]const u8, times: *[2]timeval) c_int;
|
|||||||
pub extern "c" fn utimensat(dirfd: fd_t, pathname: [*:0]const u8, times: *[2]timespec, flags: u32) c_int;
|
pub extern "c" fn utimensat(dirfd: fd_t, pathname: [*:0]const u8, times: *[2]timespec, flags: u32) c_int;
|
||||||
pub extern "c" fn futimens(fd: fd_t, times: *const [2]timespec) c_int;
|
pub extern "c" fn futimens(fd: fd_t, times: *const [2]timespec) c_int;
|
||||||
|
|
||||||
pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: fn (?*c_void) callconv(.C) ?*c_void, noalias arg: ?*c_void) c_int;
|
pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: fn (?*c_void) callconv(.C) ?*c_void, noalias arg: ?*c_void) E;
|
||||||
pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
|
pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) E;
|
||||||
pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
|
pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) E;
|
||||||
pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) c_int;
|
pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) E;
|
||||||
pub extern "c" fn pthread_attr_setguardsize(attr: *pthread_attr_t, guardsize: usize) c_int;
|
pub extern "c" fn pthread_attr_setguardsize(attr: *pthread_attr_t, guardsize: usize) E;
|
||||||
pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
|
pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) E;
|
||||||
pub extern "c" fn pthread_self() pthread_t;
|
pub extern "c" fn pthread_self() pthread_t;
|
||||||
pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
|
pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) E;
|
||||||
pub extern "c" fn pthread_detach(thread: pthread_t) c_int;
|
pub extern "c" fn pthread_detach(thread: pthread_t) E;
|
||||||
pub extern "c" fn pthread_atfork(
|
pub extern "c" fn pthread_atfork(
|
||||||
prepare: ?fn () callconv(.C) void,
|
prepare: ?fn () callconv(.C) void,
|
||||||
parent: ?fn () callconv(.C) void,
|
parent: ?fn () callconv(.C) void,
|
||||||
child: ?fn () callconv(.C) void,
|
child: ?fn () callconv(.C) void,
|
||||||
) c_int;
|
) c_int;
|
||||||
pub extern "c" fn pthread_key_create(key: *pthread_key_t, destructor: ?fn (value: *c_void) callconv(.C) void) c_int;
|
pub extern "c" fn pthread_key_create(key: *pthread_key_t, destructor: ?fn (value: *c_void) callconv(.C) void) E;
|
||||||
pub extern "c" fn pthread_key_delete(key: pthread_key_t) c_int;
|
pub extern "c" fn pthread_key_delete(key: pthread_key_t) E;
|
||||||
pub extern "c" fn pthread_getspecific(key: pthread_key_t) ?*c_void;
|
pub extern "c" fn pthread_getspecific(key: pthread_key_t) ?*c_void;
|
||||||
pub extern "c" fn pthread_setspecific(key: pthread_key_t, value: ?*c_void) c_int;
|
pub extern "c" fn pthread_setspecific(key: pthread_key_t, value: ?*c_void) c_int;
|
||||||
pub extern "c" fn sem_init(sem: *sem_t, pshared: c_int, value: c_uint) c_int;
|
pub extern "c" fn sem_init(sem: *sem_t, pshared: c_int, value: c_uint) c_int;
|
||||||
@ -339,24 +334,24 @@ pub extern "c" fn dn_expand(
|
|||||||
) c_int;
|
) c_int;
|
||||||
|
|
||||||
pub const PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{};
|
pub const PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{};
|
||||||
pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) c_int;
|
pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) E;
|
||||||
pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) c_int;
|
pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) E;
|
||||||
pub extern "c" fn pthread_mutex_trylock(mutex: *pthread_mutex_t) c_int;
|
pub extern "c" fn pthread_mutex_trylock(mutex: *pthread_mutex_t) E;
|
||||||
pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c_int;
|
pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) E;
|
||||||
|
|
||||||
pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
|
pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
|
||||||
pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c_int;
|
pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) E;
|
||||||
pub extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) c_int;
|
pub extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) E;
|
||||||
pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
|
pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) E;
|
||||||
pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c_int;
|
pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) E;
|
||||||
pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;
|
pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) E;
|
||||||
|
|
||||||
pub extern "c" fn pthread_rwlock_destroy(rwl: *pthread_rwlock_t) callconv(.C) c_int;
|
pub extern "c" fn pthread_rwlock_destroy(rwl: *pthread_rwlock_t) callconv(.C) E;
|
||||||
pub extern "c" fn pthread_rwlock_rdlock(rwl: *pthread_rwlock_t) callconv(.C) c_int;
|
pub extern "c" fn pthread_rwlock_rdlock(rwl: *pthread_rwlock_t) callconv(.C) E;
|
||||||
pub extern "c" fn pthread_rwlock_wrlock(rwl: *pthread_rwlock_t) callconv(.C) c_int;
|
pub extern "c" fn pthread_rwlock_wrlock(rwl: *pthread_rwlock_t) callconv(.C) E;
|
||||||
pub extern "c" fn pthread_rwlock_tryrdlock(rwl: *pthread_rwlock_t) callconv(.C) c_int;
|
pub extern "c" fn pthread_rwlock_tryrdlock(rwl: *pthread_rwlock_t) callconv(.C) E;
|
||||||
pub extern "c" fn pthread_rwlock_trywrlock(rwl: *pthread_rwlock_t) callconv(.C) c_int;
|
pub extern "c" fn pthread_rwlock_trywrlock(rwl: *pthread_rwlock_t) callconv(.C) E;
|
||||||
pub extern "c" fn pthread_rwlock_unlock(rwl: *pthread_rwlock_t) callconv(.C) c_int;
|
pub extern "c" fn pthread_rwlock_unlock(rwl: *pthread_rwlock_t) callconv(.C) E;
|
||||||
|
|
||||||
pub const pthread_t = *opaque {};
|
pub const pthread_t = *opaque {};
|
||||||
pub const FILE = opaque {};
|
pub const FILE = opaque {};
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
@ -193,8 +188,8 @@ pub const pthread_attr_t = extern struct {
|
|||||||
|
|
||||||
const pthread_t = std.c.pthread_t;
|
const pthread_t = std.c.pthread_t;
|
||||||
pub extern "c" fn pthread_threadid_np(thread: ?pthread_t, thread_id: *u64) c_int;
|
pub extern "c" fn pthread_threadid_np(thread: ?pthread_t, thread_id: *u64) c_int;
|
||||||
pub extern "c" fn pthread_setname_np(name: [*:0]const u8) c_int;
|
pub extern "c" fn pthread_setname_np(name: [*:0]const u8) E;
|
||||||
pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) c_int;
|
pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) E;
|
||||||
|
|
||||||
pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
|
pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
usingnamespace std.c;
|
usingnamespace std.c;
|
||||||
extern "c" threadlocal var errno: c_int;
|
extern "c" threadlocal var errno: c_int;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
pub const pthread_mutex_t = extern struct {
|
pub const pthread_mutex_t = extern struct {
|
||||||
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
usingnamespace std.c;
|
usingnamespace std.c;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
pub const pthread_mutex_t = extern struct {
|
pub const pthread_mutex_t = extern struct {
|
||||||
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
//
|
//
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
pub const pthread_mutex_t = extern struct {
|
pub const pthread_mutex_t = extern struct {
|
||||||
inner: usize = ~@as(usize, 0),
|
inner: usize = ~@as(usize, 0),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const abi = std.Target.current.abi;
|
const abi = std.Target.current.abi;
|
||||||
@ -186,8 +181,8 @@ const __SIZEOF_PTHREAD_MUTEX_T = if (os_tag == .fuchsia) 40 else switch (abi) {
|
|||||||
};
|
};
|
||||||
const __SIZEOF_SEM_T = 4 * @sizeOf(usize);
|
const __SIZEOF_SEM_T = 4 * @sizeOf(usize);
|
||||||
|
|
||||||
pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) c_int;
|
pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;
|
||||||
pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) c_int;
|
pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) E;
|
||||||
|
|
||||||
pub const RTLD_LAZY = 1;
|
pub const RTLD_LAZY = 1;
|
||||||
pub const RTLD_NOW = 2;
|
pub const RTLD_NOW = 2;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
pub const pthread_mutex_t = extern struct {
|
pub const pthread_mutex_t = extern struct {
|
||||||
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
|
|
||||||
@ -95,5 +90,5 @@ pub const pthread_attr_t = extern struct {
|
|||||||
|
|
||||||
pub const sem_t = ?*opaque {};
|
pub const sem_t = ?*opaque {};
|
||||||
|
|
||||||
pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8, arg: ?*c_void) c_int;
|
pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8, arg: ?*c_void) E;
|
||||||
pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) c_int;
|
pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) E;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
pub const pthread_mutex_t = extern struct {
|
pub const pthread_mutex_t = extern struct {
|
||||||
__pthread_mutex_flag1: u16 = 0,
|
__pthread_mutex_flag1: u16 = 0,
|
||||||
__pthread_mutex_flag2: u8 = 0,
|
__pthread_mutex_flag2: u8 = 0,
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
usingnamespace @import("../os/bits.zig");
|
usingnamespace @import("../os/bits.zig");
|
||||||
|
|
||||||
extern threadlocal var errno: c_int;
|
extern threadlocal var errno: c_int;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
pub extern "c" fn _errno() *c_int;
|
pub extern "c" fn _errno() *c_int;
|
||||||
|
|
||||||
pub extern "c" fn _msize(memblock: ?*c_void) usize;
|
pub extern "c" fn _msize(memblock: ?*c_void) usize;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const cstr = std.cstr;
|
const cstr = std.cstr;
|
||||||
const unicode = std.unicode;
|
const unicode = std.unicode;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
|
|
||||||
pub const deflate = @import("compress/deflate.zig");
|
pub const deflate = @import("compress/deflate.zig");
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
//
|
//
|
||||||
// Decompressor for DEFLATE data streams (RFC1951)
|
// Decompressor for DEFLATE data streams (RFC1951)
|
||||||
//
|
//
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
//
|
//
|
||||||
// Decompressor for GZIP data streams (RFC1952)
|
// Decompressor for GZIP data streams (RFC1952)
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
//
|
//
|
||||||
// Decompressor for ZLIB data streams (RFC1950)
|
// Decompressor for ZLIB data streams (RFC1950)
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
/// Authenticated Encryption with Associated Data
|
/// Authenticated Encryption with Associated Data
|
||||||
pub const aead = struct {
|
pub const aead = struct {
|
||||||
pub const aegis = struct {
|
pub const aegis = struct {
|
||||||
@ -110,7 +104,16 @@ pub const onetimeauth = struct {
|
|||||||
///
|
///
|
||||||
/// Password hashing functions must be used whenever sensitive data has to be directly derived from a password.
|
/// Password hashing functions must be used whenever sensitive data has to be directly derived from a password.
|
||||||
pub const pwhash = struct {
|
pub const pwhash = struct {
|
||||||
|
pub const Encoding = enum {
|
||||||
|
phc,
|
||||||
|
crypt,
|
||||||
|
};
|
||||||
|
pub const KdfError = errors.Error || std.mem.Allocator.Error;
|
||||||
|
pub const HasherError = KdfError || @import("crypto/phc_encoding.zig").Error;
|
||||||
|
pub const Error = HasherError || error{AllocatorRequired};
|
||||||
|
|
||||||
pub const bcrypt = @import("crypto/bcrypt.zig");
|
pub const bcrypt = @import("crypto/bcrypt.zig");
|
||||||
|
pub const scrypt = @import("crypto/scrypt.zig");
|
||||||
pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2;
|
pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const readIntLittle = std.mem.readIntLittle;
|
const readIntLittle = std.mem.readIntLittle;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("../../std.zig");
|
const std = @import("../../std.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("../../std.zig");
|
const std = @import("../../std.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
// Based on Go stdlib implementation
|
// Based on Go stdlib implementation
|
||||||
|
|
||||||
const std = @import("../../std.zig");
|
const std = @import("../../std.zig");
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const aes = crypto.core.aes;
|
const aes = crypto.core.aes;
|
||||||
|
|||||||
@ -1,26 +1,27 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
|
const debug = std.debug;
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const debug = std.debug;
|
const pwhash = crypto.pwhash;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const utils = crypto.utils;
|
const utils = crypto.utils;
|
||||||
const EncodingError = crypto.errors.EncodingError;
|
|
||||||
const PasswordVerificationError = crypto.errors.PasswordVerificationError;
|
const phc_format = @import("phc_encoding.zig");
|
||||||
|
|
||||||
|
const KdfError = pwhash.KdfError;
|
||||||
|
const HasherError = pwhash.HasherError;
|
||||||
|
const EncodingError = phc_format.Error;
|
||||||
|
const Error = pwhash.Error;
|
||||||
|
|
||||||
const salt_length: usize = 16;
|
const salt_length: usize = 16;
|
||||||
const salt_str_length: usize = 22;
|
const salt_str_length: usize = 22;
|
||||||
const ct_str_length: usize = 31;
|
const ct_str_length: usize = 31;
|
||||||
const ct_length: usize = 24;
|
const ct_length: usize = 24;
|
||||||
|
const dk_length: usize = ct_length - 1;
|
||||||
|
|
||||||
/// Length (in bytes) of a password hash
|
/// Length (in bytes) of a password hash in crypt encoding
|
||||||
pub const hash_length: usize = 60;
|
pub const hash_length: usize = 60;
|
||||||
|
|
||||||
const State = struct {
|
const State = struct {
|
||||||
@ -139,71 +140,15 @@ const State = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// bcrypt has its own variant of base64, with its own alphabet and no padding
|
pub const Params = struct {
|
||||||
const Codec = struct {
|
rounds_log: u6,
|
||||||
const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
||||||
|
|
||||||
fn encode(b64: []u8, bin: []const u8) void {
|
|
||||||
var i: usize = 0;
|
|
||||||
var j: usize = 0;
|
|
||||||
while (i < bin.len) {
|
|
||||||
var c1 = bin[i];
|
|
||||||
i += 1;
|
|
||||||
b64[j] = alphabet[c1 >> 2];
|
|
||||||
j += 1;
|
|
||||||
c1 = (c1 & 3) << 4;
|
|
||||||
if (i >= bin.len) {
|
|
||||||
b64[j] = alphabet[c1];
|
|
||||||
j += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var c2 = bin[i];
|
|
||||||
i += 1;
|
|
||||||
c1 |= (c2 >> 4) & 0x0f;
|
|
||||||
b64[j] = alphabet[c1];
|
|
||||||
j += 1;
|
|
||||||
c1 = (c2 & 0x0f) << 2;
|
|
||||||
if (i >= bin.len) {
|
|
||||||
b64[j] = alphabet[c1];
|
|
||||||
j += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c2 = bin[i];
|
|
||||||
i += 1;
|
|
||||||
c1 |= (c2 >> 6) & 3;
|
|
||||||
b64[j] = alphabet[c1];
|
|
||||||
b64[j + 1] = alphabet[c2 & 0x3f];
|
|
||||||
j += 2;
|
|
||||||
}
|
|
||||||
debug.assert(j == b64.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode(bin: []u8, b64: []const u8) EncodingError!void {
|
|
||||||
var i: usize = 0;
|
|
||||||
var j: usize = 0;
|
|
||||||
while (j < bin.len) {
|
|
||||||
const c1 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i]) orelse return error.InvalidEncoding);
|
|
||||||
const c2 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 1]) orelse return error.InvalidEncoding);
|
|
||||||
bin[j] = (c1 << 2) | ((c2 & 0x30) >> 4);
|
|
||||||
j += 1;
|
|
||||||
if (j >= bin.len) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const c3 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 2]) orelse return error.InvalidEncoding);
|
|
||||||
bin[j] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
|
|
||||||
j += 1;
|
|
||||||
if (j >= bin.len) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const c4 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 3]) orelse return error.InvalidEncoding);
|
|
||||||
bin[j] = ((c3 & 0x03) << 6) | c4;
|
|
||||||
j += 1;
|
|
||||||
i += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8) ![hash_length]u8 {
|
pub fn bcrypt(
|
||||||
|
password: []const u8,
|
||||||
|
salt: [salt_length]u8,
|
||||||
|
params: Params,
|
||||||
|
) [dk_length]u8 {
|
||||||
var state = State{};
|
var state = State{};
|
||||||
var password_buf: [73]u8 = undefined;
|
var password_buf: [73]u8 = undefined;
|
||||||
const trimmed_len = math.min(password.len, password_buf.len - 1);
|
const trimmed_len = math.min(password.len, password_buf.len - 1);
|
||||||
@ -212,7 +157,7 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)
|
|||||||
var passwordZ = password_buf[0 .. trimmed_len + 1];
|
var passwordZ = password_buf[0 .. trimmed_len + 1];
|
||||||
state.expand(salt[0..], passwordZ);
|
state.expand(salt[0..], passwordZ);
|
||||||
|
|
||||||
const rounds: u64 = @as(u64, 1) << rounds_log;
|
const rounds: u64 = @as(u64, 1) << params.rounds_log;
|
||||||
var k: u64 = 0;
|
var k: u64 = 0;
|
||||||
while (k < rounds) : (k += 1) {
|
while (k < rounds) : (k += 1) {
|
||||||
state.expand0(passwordZ);
|
state.expand0(passwordZ);
|
||||||
@ -230,19 +175,204 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)
|
|||||||
for (cdata) |c, i| {
|
for (cdata) |c, i| {
|
||||||
mem.writeIntBig(u32, ct[i * 4 ..][0..4], c);
|
mem.writeIntBig(u32, ct[i * 4 ..][0..4], c);
|
||||||
}
|
}
|
||||||
|
return ct[0..dk_length].*;
|
||||||
var salt_str: [salt_str_length]u8 = undefined;
|
|
||||||
Codec.encode(salt_str[0..], salt[0..]);
|
|
||||||
|
|
||||||
var ct_str: [ct_str_length]u8 = undefined;
|
|
||||||
Codec.encode(ct_str[0..], ct[0 .. ct.len - 1]);
|
|
||||||
|
|
||||||
var s_buf: [hash_length]u8 = undefined;
|
|
||||||
const s = fmt.bufPrint(s_buf[0..], "$2b${d}{d}${s}{s}", .{ rounds_log / 10, rounds_log % 10, salt_str, ct_str }) catch unreachable;
|
|
||||||
debug.assert(s.len == s_buf.len);
|
|
||||||
return s_buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const crypt_format = struct {
|
||||||
|
/// String prefix for bcrypt
|
||||||
|
pub const prefix = "$2";
|
||||||
|
|
||||||
|
// bcrypt has its own variant of base64, with its own alphabet and no padding
|
||||||
|
const Codec = struct {
|
||||||
|
const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
||||||
|
fn encode(b64: []u8, bin: []const u8) void {
|
||||||
|
var i: usize = 0;
|
||||||
|
var j: usize = 0;
|
||||||
|
while (i < bin.len) {
|
||||||
|
var c1 = bin[i];
|
||||||
|
i += 1;
|
||||||
|
b64[j] = alphabet[c1 >> 2];
|
||||||
|
j += 1;
|
||||||
|
c1 = (c1 & 3) << 4;
|
||||||
|
if (i >= bin.len) {
|
||||||
|
b64[j] = alphabet[c1];
|
||||||
|
j += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var c2 = bin[i];
|
||||||
|
i += 1;
|
||||||
|
c1 |= (c2 >> 4) & 0x0f;
|
||||||
|
b64[j] = alphabet[c1];
|
||||||
|
j += 1;
|
||||||
|
c1 = (c2 & 0x0f) << 2;
|
||||||
|
if (i >= bin.len) {
|
||||||
|
b64[j] = alphabet[c1];
|
||||||
|
j += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c2 = bin[i];
|
||||||
|
i += 1;
|
||||||
|
c1 |= (c2 >> 6) & 3;
|
||||||
|
b64[j] = alphabet[c1];
|
||||||
|
b64[j + 1] = alphabet[c2 & 0x3f];
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
debug.assert(j == b64.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(bin: []u8, b64: []const u8) EncodingError!void {
|
||||||
|
var i: usize = 0;
|
||||||
|
var j: usize = 0;
|
||||||
|
while (j < bin.len) {
|
||||||
|
const c1 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i]) orelse
|
||||||
|
return EncodingError.InvalidEncoding);
|
||||||
|
const c2 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 1]) orelse
|
||||||
|
return EncodingError.InvalidEncoding);
|
||||||
|
bin[j] = (c1 << 2) | ((c2 & 0x30) >> 4);
|
||||||
|
j += 1;
|
||||||
|
if (j >= bin.len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const c3 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 2]) orelse
|
||||||
|
return EncodingError.InvalidEncoding);
|
||||||
|
bin[j] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
|
||||||
|
j += 1;
|
||||||
|
if (j >= bin.len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const c4 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 3]) orelse
|
||||||
|
return EncodingError.InvalidEncoding);
|
||||||
|
bin[j] = ((c3 & 0x03) << 6) | c4;
|
||||||
|
j += 1;
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn strHashInternal(
|
||||||
|
password: []const u8,
|
||||||
|
salt: [salt_length]u8,
|
||||||
|
params: Params,
|
||||||
|
) [hash_length]u8 {
|
||||||
|
var dk = bcrypt(password, salt, params);
|
||||||
|
|
||||||
|
var salt_str: [salt_str_length]u8 = undefined;
|
||||||
|
Codec.encode(salt_str[0..], salt[0..]);
|
||||||
|
|
||||||
|
var ct_str: [ct_str_length]u8 = undefined;
|
||||||
|
Codec.encode(ct_str[0..], dk[0..]);
|
||||||
|
|
||||||
|
var s_buf: [hash_length]u8 = undefined;
|
||||||
|
const s = fmt.bufPrint(
|
||||||
|
s_buf[0..],
|
||||||
|
"{s}b${d}{d}${s}{s}",
|
||||||
|
.{ prefix, params.rounds_log / 10, params.rounds_log % 10, salt_str, ct_str },
|
||||||
|
) catch unreachable;
|
||||||
|
debug.assert(s.len == s_buf.len);
|
||||||
|
return s_buf;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Hash and verify passwords using the PHC format.
|
||||||
|
const PhcFormatHasher = struct {
|
||||||
|
const alg_id = "bcrypt";
|
||||||
|
const BinValue = phc_format.BinValue;
|
||||||
|
|
||||||
|
const HashResult = struct {
|
||||||
|
alg_id: []const u8,
|
||||||
|
r: u6,
|
||||||
|
salt: BinValue(salt_length),
|
||||||
|
hash: BinValue(dk_length),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Return a non-deterministic hash of the password encoded as a PHC-format string
|
||||||
|
pub fn create(
|
||||||
|
password: []const u8,
|
||||||
|
params: Params,
|
||||||
|
buf: []u8,
|
||||||
|
) HasherError![]const u8 {
|
||||||
|
var salt: [salt_length]u8 = undefined;
|
||||||
|
crypto.random.bytes(&salt);
|
||||||
|
|
||||||
|
const hash = bcrypt(password, salt, params);
|
||||||
|
|
||||||
|
return phc_format.serialize(HashResult{
|
||||||
|
.alg_id = alg_id,
|
||||||
|
.r = params.rounds_log,
|
||||||
|
.salt = try BinValue(salt_length).fromSlice(&salt),
|
||||||
|
.hash = try BinValue(dk_length).fromSlice(&hash),
|
||||||
|
}, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a password against a PHC-format encoded string
|
||||||
|
pub fn verify(
|
||||||
|
str: []const u8,
|
||||||
|
password: []const u8,
|
||||||
|
) HasherError!void {
|
||||||
|
const hash_result = try phc_format.deserialize(HashResult, str);
|
||||||
|
|
||||||
|
if (!mem.eql(u8, hash_result.alg_id, alg_id)) return HasherError.PasswordVerificationFailed;
|
||||||
|
if (hash_result.salt.len != salt_length or hash_result.hash.len != dk_length)
|
||||||
|
return HasherError.InvalidEncoding;
|
||||||
|
|
||||||
|
const hash = bcrypt(password, hash_result.salt.buf, .{ .rounds_log = hash_result.r });
|
||||||
|
const expected_hash = hash_result.hash.constSlice();
|
||||||
|
|
||||||
|
if (!mem.eql(u8, &hash, expected_hash)) return HasherError.PasswordVerificationFailed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Hash and verify passwords using the modular crypt format.
|
||||||
|
const CryptFormatHasher = struct {
|
||||||
|
/// Length of a string returned by the create() function
|
||||||
|
pub const pwhash_str_length: usize = hash_length;
|
||||||
|
|
||||||
|
/// Return a non-deterministic hash of the password encoded into the modular crypt format
|
||||||
|
pub fn create(
|
||||||
|
password: []const u8,
|
||||||
|
params: Params,
|
||||||
|
buf: []u8,
|
||||||
|
) HasherError![]const u8 {
|
||||||
|
if (buf.len < pwhash_str_length) return HasherError.NoSpaceLeft;
|
||||||
|
|
||||||
|
var salt: [salt_length]u8 = undefined;
|
||||||
|
crypto.random.bytes(&salt);
|
||||||
|
|
||||||
|
const hash = crypt_format.strHashInternal(password, salt, params);
|
||||||
|
mem.copy(u8, buf, &hash);
|
||||||
|
|
||||||
|
return buf[0..pwhash_str_length];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a password against a string in modular crypt format
|
||||||
|
pub fn verify(
|
||||||
|
str: []const u8,
|
||||||
|
password: []const u8,
|
||||||
|
) HasherError!void {
|
||||||
|
if (str.len != pwhash_str_length or str[3] != '$' or str[6] != '$')
|
||||||
|
return HasherError.InvalidEncoding;
|
||||||
|
|
||||||
|
const rounds_log_str = str[4..][0..2];
|
||||||
|
const rounds_log = fmt.parseInt(u6, rounds_log_str[0..], 10) catch
|
||||||
|
return HasherError.InvalidEncoding;
|
||||||
|
|
||||||
|
const salt_str = str[7..][0..salt_str_length];
|
||||||
|
var salt: [salt_length]u8 = undefined;
|
||||||
|
try crypt_format.Codec.decode(salt[0..], salt_str[0..]);
|
||||||
|
|
||||||
|
const wanted_s = crypt_format.strHashInternal(password, salt, .{ .rounds_log = rounds_log });
|
||||||
|
if (!mem.eql(u8, wanted_s[0..], str[0..])) return HasherError.PasswordVerificationFailed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for hashing a password.
|
||||||
|
pub const HashOptions = struct {
|
||||||
|
allocator: ?*mem.Allocator = null,
|
||||||
|
params: Params,
|
||||||
|
encoding: pwhash.Encoding,
|
||||||
|
};
|
||||||
|
|
||||||
/// Compute a hash of a password using 2^rounds_log rounds of the bcrypt key stretching function.
|
/// Compute a hash of a password using 2^rounds_log rounds of the bcrypt key stretching function.
|
||||||
/// bcrypt is a computationally expensive and cache-hard function, explicitly designed to slow down exhaustive searches.
|
/// bcrypt is a computationally expensive and cache-hard function, explicitly designed to slow down exhaustive searches.
|
||||||
///
|
///
|
||||||
@ -251,24 +381,32 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)
|
|||||||
/// IMPORTANT: by design, bcrypt silently truncates passwords to 72 bytes.
|
/// IMPORTANT: by design, bcrypt silently truncates passwords to 72 bytes.
|
||||||
/// If this is an issue for your application, hash the password first using a function such as SHA-512,
|
/// If this is an issue for your application, hash the password first using a function such as SHA-512,
|
||||||
/// and then use the resulting hash as the password parameter for bcrypt.
|
/// and then use the resulting hash as the password parameter for bcrypt.
|
||||||
pub fn strHash(password: []const u8, rounds_log: u6) ![hash_length]u8 {
|
pub fn strHash(
|
||||||
var salt: [salt_length]u8 = undefined;
|
password: []const u8,
|
||||||
crypto.random.bytes(&salt);
|
options: HashOptions,
|
||||||
return strHashInternal(password, rounds_log, salt);
|
out: []u8,
|
||||||
|
) Error![]const u8 {
|
||||||
|
switch (options.encoding) {
|
||||||
|
.phc => return PhcFormatHasher.create(password, options.params, out),
|
||||||
|
.crypt => return CryptFormatHasher.create(password, options.params, out),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Options for hash verification.
|
||||||
|
pub const VerifyOptions = struct {
|
||||||
|
allocator: ?*mem.Allocator = null,
|
||||||
|
};
|
||||||
|
|
||||||
/// Verify that a previously computed hash is valid for a given password.
|
/// Verify that a previously computed hash is valid for a given password.
|
||||||
pub fn strVerify(h: [hash_length]u8, password: []const u8) (EncodingError || PasswordVerificationError)!void {
|
pub fn strVerify(
|
||||||
if (!mem.eql(u8, "$2", h[0..2])) return error.InvalidEncoding;
|
str: []const u8,
|
||||||
if (h[3] != '$' or h[6] != '$') return error.InvalidEncoding;
|
password: []const u8,
|
||||||
const rounds_log_str = h[4..][0..2];
|
_: VerifyOptions,
|
||||||
const salt_str = h[7..][0..salt_str_length];
|
) Error!void {
|
||||||
var salt: [salt_length]u8 = undefined;
|
if (mem.startsWith(u8, str, crypt_format.prefix)) {
|
||||||
try Codec.decode(salt[0..], salt_str[0..]);
|
return CryptFormatHasher.verify(str, password);
|
||||||
const rounds_log = fmt.parseInt(u6, rounds_log_str[0..], 10) catch return error.InvalidEncoding;
|
} else {
|
||||||
const wanted_s = try strHashInternal(password, rounds_log, salt);
|
return PhcFormatHasher.verify(str, password);
|
||||||
if (!mem.eql(u8, wanted_s[0..], h[0..])) {
|
|
||||||
return error.PasswordVerificationFailed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,20 +414,71 @@ test "bcrypt codec" {
|
|||||||
var salt: [salt_length]u8 = undefined;
|
var salt: [salt_length]u8 = undefined;
|
||||||
crypto.random.bytes(&salt);
|
crypto.random.bytes(&salt);
|
||||||
var salt_str: [salt_str_length]u8 = undefined;
|
var salt_str: [salt_str_length]u8 = undefined;
|
||||||
Codec.encode(salt_str[0..], salt[0..]);
|
crypt_format.Codec.encode(salt_str[0..], salt[0..]);
|
||||||
var salt2: [salt_length]u8 = undefined;
|
var salt2: [salt_length]u8 = undefined;
|
||||||
try Codec.decode(salt2[0..], salt_str[0..]);
|
try crypt_format.Codec.decode(salt2[0..], salt_str[0..]);
|
||||||
try testing.expectEqualSlices(u8, salt[0..], salt2[0..]);
|
try testing.expectEqualSlices(u8, salt[0..], salt2[0..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "bcrypt" {
|
test "bcrypt crypt format" {
|
||||||
const s = try strHash("password", 5);
|
const hash_options = HashOptions{
|
||||||
try strVerify(s, "password");
|
.params = .{ .rounds_log = 5 },
|
||||||
try testing.expectError(error.PasswordVerificationFailed, strVerify(s, "invalid password"));
|
.encoding = .crypt,
|
||||||
|
};
|
||||||
|
const verify_options = VerifyOptions{};
|
||||||
|
|
||||||
const long_s = try strHash("password" ** 100, 5);
|
var buf: [hash_length]u8 = undefined;
|
||||||
try strVerify(long_s, "password" ** 100);
|
const s = try strHash("password", hash_options, &buf);
|
||||||
try strVerify(long_s, "password" ** 101);
|
|
||||||
|
|
||||||
try strVerify("$2b$08$WUQKyBCaKpziCwUXHiMVvu40dYVjkTxtWJlftl0PpjY2BxWSvFIEe".*, "The devil himself");
|
try testing.expect(mem.startsWith(u8, s, crypt_format.prefix));
|
||||||
|
try strVerify(s, "password", verify_options);
|
||||||
|
try testing.expectError(
|
||||||
|
error.PasswordVerificationFailed,
|
||||||
|
strVerify(s, "invalid password", verify_options),
|
||||||
|
);
|
||||||
|
|
||||||
|
var long_buf: [hash_length]u8 = undefined;
|
||||||
|
const long_s = try strHash("password" ** 100, hash_options, &long_buf);
|
||||||
|
|
||||||
|
try testing.expect(mem.startsWith(u8, long_s, crypt_format.prefix));
|
||||||
|
try strVerify(long_s, "password" ** 100, verify_options);
|
||||||
|
try strVerify(long_s, "password" ** 101, verify_options);
|
||||||
|
|
||||||
|
try strVerify(
|
||||||
|
"$2b$08$WUQKyBCaKpziCwUXHiMVvu40dYVjkTxtWJlftl0PpjY2BxWSvFIEe",
|
||||||
|
"The devil himself",
|
||||||
|
verify_options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "bcrypt phc format" {
|
||||||
|
const hash_options = HashOptions{
|
||||||
|
.params = .{ .rounds_log = 5 },
|
||||||
|
.encoding = .phc,
|
||||||
|
};
|
||||||
|
const verify_options = VerifyOptions{};
|
||||||
|
const prefix = "$bcrypt$";
|
||||||
|
|
||||||
|
var buf: [hash_length * 2]u8 = undefined;
|
||||||
|
const s = try strHash("password", hash_options, &buf);
|
||||||
|
|
||||||
|
try testing.expect(mem.startsWith(u8, s, prefix));
|
||||||
|
try strVerify(s, "password", verify_options);
|
||||||
|
try testing.expectError(
|
||||||
|
error.PasswordVerificationFailed,
|
||||||
|
strVerify(s, "invalid password", verify_options),
|
||||||
|
);
|
||||||
|
|
||||||
|
var long_buf: [hash_length * 2]u8 = undefined;
|
||||||
|
const long_s = try strHash("password" ** 100, hash_options, &long_buf);
|
||||||
|
|
||||||
|
try testing.expect(mem.startsWith(u8, long_s, prefix));
|
||||||
|
try strVerify(long_s, "password" ** 100, verify_options);
|
||||||
|
try strVerify(long_s, "password" ** 101, verify_options);
|
||||||
|
|
||||||
|
try strVerify(
|
||||||
|
"$bcrypt$r=5$2NopntlgE2lX3cTwr4qz8A$r3T7iKYQNnY4hAhGjk9RmuyvgrYJZwc",
|
||||||
|
"The devil himself",
|
||||||
|
verify_options,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
// zig run benchmark.zig --release-fast --zig-lib-dir ..
|
// zig run benchmark.zig --release-fast --zig-lib-dir ..
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
@ -300,6 +295,43 @@ pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {
|
|||||||
return throughput;
|
return throughput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CryptoPwhash = struct {
|
||||||
|
hashFn: anytype,
|
||||||
|
params: anytype,
|
||||||
|
name: []const u8,
|
||||||
|
};
|
||||||
|
const bcrypt_params = bcrypt.Params{ .rounds_log = 5 };
|
||||||
|
const pwhashes = [_]CryptoPwhash{
|
||||||
|
CryptoPwhash{ .hashFn = bcrypt.strHash, .params = bcrypt_params, .name = "bcrypt" },
|
||||||
|
CryptoPwhash{ .hashFn = scrypt.strHash, .params = scrypt.Params.interactive, .name = "scrypt" },
|
||||||
|
};
|
||||||
|
|
||||||
|
fn benchmarkPwhash(
|
||||||
|
comptime hashFn: anytype,
|
||||||
|
comptime params: anytype,
|
||||||
|
comptime count: comptime_int,
|
||||||
|
) !u64 {
|
||||||
|
const password = "testpass" ** 2;
|
||||||
|
const opts = .{ .allocator = std.testing.allocator, .params = params, .encoding = .phc };
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
|
||||||
|
var timer = try Timer.start();
|
||||||
|
const start = timer.lap();
|
||||||
|
{
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < count) : (i += 1) {
|
||||||
|
_ = try hashFn(password, opts, &buf);
|
||||||
|
mem.doNotOptimizeAway(&buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const end = timer.read();
|
||||||
|
|
||||||
|
const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
|
||||||
|
const throughput = @floatToInt(u64, count / elapsed_s);
|
||||||
|
|
||||||
|
return throughput;
|
||||||
|
}
|
||||||
|
|
||||||
fn usage() void {
|
fn usage() void {
|
||||||
std.debug.warn(
|
std.debug.warn(
|
||||||
\\throughput_test [options]
|
\\throughput_test [options]
|
||||||
@ -418,4 +450,11 @@ pub fn main() !void {
|
|||||||
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline for (pwhashes) |H| {
|
||||||
|
if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
|
||||||
|
const throughput = try benchmarkPwhash(H.hashFn, H.params, mode(64));
|
||||||
|
try stdout.print("{s:>17}: {:10} ops/s\n", .{ H.name, throughput });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
// Translated from BLAKE3 reference implementation.
|
// Translated from BLAKE3 reference implementation.
|
||||||
// Source: https://github.com/BLAKE3-team/BLAKE3
|
// Source: https://github.com/BLAKE3-team/BLAKE3
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
// Based on public domain Supercop by Daniel J. Bernstein
|
// Based on public domain Supercop by Daniel J. Bernstein
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
//
|
//
|
||||||
// Adapted from BearSSL's ctmul64 implementation originally written by Thomas Pornin <pornin@bolet.org>
|
// Adapted from BearSSL's ctmul64 implementation originally written by Thomas Pornin <pornin@bolet.org>
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
// Gimli is a 384-bit permutation designed to achieve high security with high
|
// Gimli is a 384-bit permutation designed to achieve high security with high
|
||||||
// performance across a broad range of platforms, including 64-bit Intel/AMD
|
// performance across a broad range of platforms, including 64-bit Intel/AMD
|
||||||
// server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
|
// server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const hmac = std.crypto.auth.hmac;
|
const hmac = std.crypto.auth.hmac;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
// Based on Go stdlib implementation
|
// Based on Go stdlib implementation
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const common = @import("../common.zig");
|
const common = @import("../common.zig");
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = std.builtin;
|
const builtin = std.builtin;
|
||||||
const common = @import("../common.zig");
|
const common = @import("../common.zig");
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|||||||
371
lib/std/crypto/phc_encoding.zig
Normal file
371
lib/std/crypto/phc_encoding.zig
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
// https://github.com/P-H-C/phc-string-format
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const fmt = std.fmt;
|
||||||
|
const io = std.io;
|
||||||
|
const mem = std.mem;
|
||||||
|
const meta = std.meta;
|
||||||
|
|
||||||
|
const fields_delimiter = "$";
|
||||||
|
const version_param_name = "v";
|
||||||
|
const params_delimiter = ",";
|
||||||
|
const kv_delimiter = "=";
|
||||||
|
|
||||||
|
pub const Error = std.crypto.errors.EncodingError || error{NoSpaceLeft};
|
||||||
|
|
||||||
|
const B64Decoder = std.base64.standard_no_pad.Decoder;
|
||||||
|
const B64Encoder = std.base64.standard_no_pad.Encoder;
|
||||||
|
|
||||||
|
/// A wrapped binary value whose maximum size is `max_len`.
|
||||||
|
///
|
||||||
|
/// This type must be used whenever a binary value is encoded in a PHC-formatted string.
|
||||||
|
/// This includes `salt`, `hash`, and any other binary parameters such as keys.
|
||||||
|
///
|
||||||
|
/// Once initialized, the actual value can be read with the `constSlice()` function.
|
||||||
|
pub fn BinValue(comptime max_len: usize) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
const capacity = max_len;
|
||||||
|
const max_encoded_length = B64Encoder.calcSize(max_len);
|
||||||
|
|
||||||
|
buf: [max_len]u8 = undefined,
|
||||||
|
len: usize = 0,
|
||||||
|
|
||||||
|
/// Wrap an existing byte slice
|
||||||
|
pub fn fromSlice(slice: []const u8) Error!Self {
|
||||||
|
if (slice.len > capacity) return Error.NoSpaceLeft;
|
||||||
|
var bin_value: Self = undefined;
|
||||||
|
mem.copy(u8, &bin_value.buf, slice);
|
||||||
|
bin_value.len = slice.len;
|
||||||
|
return bin_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the slice containing the actual value.
|
||||||
|
pub fn constSlice(self: Self) []const u8 {
|
||||||
|
return self.buf[0..self.len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fromB64(self: *Self, str: []const u8) !void {
|
||||||
|
const len = B64Decoder.calcSizeForSlice(str) catch return Error.InvalidEncoding;
|
||||||
|
if (len > self.buf.len) return Error.NoSpaceLeft;
|
||||||
|
B64Decoder.decode(&self.buf, str) catch return Error.InvalidEncoding;
|
||||||
|
self.len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toB64(self: Self, buf: []u8) ![]const u8 {
|
||||||
|
const value = self.constSlice();
|
||||||
|
const len = B64Encoder.calcSize(value.len);
|
||||||
|
if (len > buf.len) return Error.NoSpaceLeft;
|
||||||
|
return B64Encoder.encode(buf, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize a PHC-formatted string into a structure `HashResult`.
|
||||||
|
///
|
||||||
|
/// Required field in the `HashResult` structure:
|
||||||
|
/// - `alg_id`: algorithm identifier
|
||||||
|
/// Optional, special fields:
|
||||||
|
/// - `alg_version`: algorithm version (unsigned integer)
|
||||||
|
/// - `salt`: salt
|
||||||
|
/// - `hash`: output of the hash function
|
||||||
|
///
|
||||||
|
/// Other fields will also be deserialized from the function parameters section.
|
||||||
|
pub fn deserialize(comptime HashResult: type, str: []const u8) Error!HashResult {
|
||||||
|
var out = mem.zeroes(HashResult);
|
||||||
|
var it = mem.split(u8, str, fields_delimiter);
|
||||||
|
var set_fields: usize = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Read the algorithm identifier
|
||||||
|
if ((it.next() orelse return Error.InvalidEncoding).len != 0) return Error.InvalidEncoding;
|
||||||
|
out.alg_id = it.next() orelse return Error.InvalidEncoding;
|
||||||
|
set_fields += 1;
|
||||||
|
|
||||||
|
// Read the optional version number
|
||||||
|
var field = it.next() orelse break;
|
||||||
|
if (kvSplit(field)) |opt_version| {
|
||||||
|
if (mem.eql(u8, opt_version.key, version_param_name)) {
|
||||||
|
if (@hasField(HashResult, "alg_version")) {
|
||||||
|
const value_type_info = switch (@typeInfo(@TypeOf(out.alg_version))) {
|
||||||
|
.Optional => |opt| comptime @typeInfo(opt.child),
|
||||||
|
else => |t| t,
|
||||||
|
};
|
||||||
|
out.alg_version = fmt.parseUnsigned(
|
||||||
|
@Type(value_type_info),
|
||||||
|
opt_version.value,
|
||||||
|
10,
|
||||||
|
) catch return Error.InvalidEncoding;
|
||||||
|
set_fields += 1;
|
||||||
|
}
|
||||||
|
field = it.next() orelse break;
|
||||||
|
}
|
||||||
|
} else |_| {}
|
||||||
|
|
||||||
|
// Read optional parameters
|
||||||
|
var has_params = false;
|
||||||
|
var it_params = mem.split(u8, field, params_delimiter);
|
||||||
|
while (it_params.next()) |params| {
|
||||||
|
const param = kvSplit(params) catch break;
|
||||||
|
var found = false;
|
||||||
|
inline for (comptime meta.fields(HashResult)) |p| {
|
||||||
|
if (mem.eql(u8, p.name, param.key)) {
|
||||||
|
switch (@typeInfo(p.field_type)) {
|
||||||
|
.Int => @field(out, p.name) = fmt.parseUnsigned(
|
||||||
|
p.field_type,
|
||||||
|
param.value,
|
||||||
|
10,
|
||||||
|
) catch return Error.InvalidEncoding,
|
||||||
|
.Pointer => |ptr| {
|
||||||
|
if (!ptr.is_const) @compileError("Value slice must be constant");
|
||||||
|
@field(out, p.name) = param.value;
|
||||||
|
},
|
||||||
|
.Struct => try @field(out, p.name).fromB64(param.value),
|
||||||
|
else => std.debug.panic(
|
||||||
|
"Value for [{s}] must be an integer, a constant slice or a BinValue",
|
||||||
|
.{p.name},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
set_fields += 1;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) return Error.InvalidEncoding; // An unexpected parameter was found in the string
|
||||||
|
has_params = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No separator between an empty parameters set and the salt
|
||||||
|
if (has_params) field = it.next() orelse break;
|
||||||
|
|
||||||
|
// Read an optional salt
|
||||||
|
if (@hasField(HashResult, "salt")) {
|
||||||
|
try out.salt.fromB64(field);
|
||||||
|
set_fields += 1;
|
||||||
|
} else {
|
||||||
|
return Error.InvalidEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read an optional hash
|
||||||
|
field = it.next() orelse break;
|
||||||
|
if (@hasField(HashResult, "hash")) {
|
||||||
|
try out.hash.fromB64(field);
|
||||||
|
set_fields += 1;
|
||||||
|
} else {
|
||||||
|
return Error.InvalidEncoding;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that all the required fields have been set, excluding optional values and parameters
|
||||||
|
// with default values
|
||||||
|
var expected_fields: usize = 0;
|
||||||
|
inline for (comptime meta.fields(HashResult)) |p| {
|
||||||
|
if (@typeInfo(p.field_type) != .Optional and p.default_value == null) {
|
||||||
|
expected_fields += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (set_fields < expected_fields) return Error.InvalidEncoding;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize parameters into a PHC string.
|
||||||
|
///
|
||||||
|
/// Required field for `params`:
|
||||||
|
/// - `alg_id`: algorithm identifier
|
||||||
|
/// Optional, special fields:
|
||||||
|
/// - `alg_version`: algorithm version (unsigned integer)
|
||||||
|
/// - `salt`: salt
|
||||||
|
/// - `hash`: output of the hash function
|
||||||
|
///
|
||||||
|
/// `params` can also include any additional parameters.
|
||||||
|
pub fn serialize(params: anytype, str: []u8) Error![]const u8 {
|
||||||
|
var buf = io.fixedBufferStream(str);
|
||||||
|
try serializeTo(params, buf.writer());
|
||||||
|
return buf.getWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the number of bytes required to serialize `params`
|
||||||
|
pub fn calcSize(params: anytype) usize {
|
||||||
|
var buf = io.countingWriter(io.null_writer);
|
||||||
|
serializeTo(params, buf.writer()) catch unreachable;
|
||||||
|
return @intCast(usize, buf.bytes_written);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serializeTo(params: anytype, out: anytype) !void {
|
||||||
|
const HashResult = @TypeOf(params);
|
||||||
|
try out.writeAll(fields_delimiter);
|
||||||
|
try out.writeAll(params.alg_id);
|
||||||
|
|
||||||
|
if (@hasField(HashResult, "alg_version")) {
|
||||||
|
if (@typeInfo(@TypeOf(params.alg_version)) == .Optional) {
|
||||||
|
if (params.alg_version) |alg_version| {
|
||||||
|
try out.print(
|
||||||
|
"{s}{s}{s}{}",
|
||||||
|
.{ fields_delimiter, version_param_name, kv_delimiter, alg_version },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try out.print(
|
||||||
|
"{s}{s}{s}{}",
|
||||||
|
.{ fields_delimiter, version_param_name, kv_delimiter, params.alg_version },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var has_params = false;
|
||||||
|
inline for (comptime meta.fields(HashResult)) |p| {
|
||||||
|
if (!(mem.eql(u8, p.name, "alg_id") or
|
||||||
|
mem.eql(u8, p.name, "alg_version") or
|
||||||
|
mem.eql(u8, p.name, "hash") or
|
||||||
|
mem.eql(u8, p.name, "salt")))
|
||||||
|
{
|
||||||
|
const value = @field(params, p.name);
|
||||||
|
try out.writeAll(if (has_params) params_delimiter else fields_delimiter);
|
||||||
|
if (@typeInfo(p.field_type) == .Struct) {
|
||||||
|
var buf: [@TypeOf(value).max_encoded_length]u8 = undefined;
|
||||||
|
try out.print("{s}{s}{s}", .{ p.name, kv_delimiter, try value.toB64(&buf) });
|
||||||
|
} else {
|
||||||
|
try out.print(
|
||||||
|
if (@typeInfo(@TypeOf(value)) == .Pointer) "{s}{s}{s}" else "{s}{s}{}",
|
||||||
|
.{ p.name, kv_delimiter, value },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
has_params = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var has_salt = false;
|
||||||
|
if (@hasField(HashResult, "salt")) {
|
||||||
|
var buf: [@TypeOf(params.salt).max_encoded_length]u8 = undefined;
|
||||||
|
try out.print("{s}{s}", .{ fields_delimiter, try params.salt.toB64(&buf) });
|
||||||
|
has_salt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@hasField(HashResult, "hash")) {
|
||||||
|
var buf: [@TypeOf(params.hash).max_encoded_length]u8 = undefined;
|
||||||
|
if (!has_salt) try out.writeAll(fields_delimiter);
|
||||||
|
try out.print("{s}{s}", .{ fields_delimiter, try params.hash.toB64(&buf) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split a `key=value` string into `key` and `value`
|
||||||
|
fn kvSplit(str: []const u8) !struct { key: []const u8, value: []const u8 } {
|
||||||
|
var it = mem.split(u8, str, kv_delimiter);
|
||||||
|
const key = it.next() orelse return Error.InvalidEncoding;
|
||||||
|
const value = it.next() orelse return Error.InvalidEncoding;
|
||||||
|
const ret = .{ .key = key, .value = value };
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "phc format - encoding/decoding" {
|
||||||
|
const Input = struct {
|
||||||
|
str: []const u8,
|
||||||
|
HashResult: type,
|
||||||
|
};
|
||||||
|
const inputs = [_]Input{
|
||||||
|
.{
|
||||||
|
.str = "$argon2id$v=19$key=a2V5,m=4096,t=0,p=1$X1NhbHQAAAAAAAAAAAAAAA$bWh++MKN1OiFHKgIWTLvIi1iHicmHH7+Fv3K88ifFfI",
|
||||||
|
.HashResult = struct {
|
||||||
|
alg_id: []const u8,
|
||||||
|
alg_version: u16,
|
||||||
|
key: BinValue(16),
|
||||||
|
m: usize,
|
||||||
|
t: u64,
|
||||||
|
p: u32,
|
||||||
|
salt: BinValue(16),
|
||||||
|
hash: BinValue(32),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$v=1$ln=15,r=8,p=1$c2FsdHNhbHQ$dGVzdHBhc3M",
|
||||||
|
.HashResult = struct {
|
||||||
|
alg_id: []const u8,
|
||||||
|
alg_version: ?u30,
|
||||||
|
ln: u6,
|
||||||
|
r: u30,
|
||||||
|
p: u30,
|
||||||
|
salt: BinValue(16),
|
||||||
|
hash: BinValue(16),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt",
|
||||||
|
.HashResult = struct { alg_id: []const u8 },
|
||||||
|
},
|
||||||
|
.{ .str = "$scrypt$v=1", .HashResult = struct { alg_id: []const u8, alg_version: u16 } },
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$ln=15,r=8,p=1",
|
||||||
|
.HashResult = struct { alg_id: []const u8, alg_version: ?u30, ln: u6, r: u30, p: u30 },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$c2FsdHNhbHQ",
|
||||||
|
.HashResult = struct { alg_id: []const u8, salt: BinValue(16) },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$v=1$ln=15,r=8,p=1$c2FsdHNhbHQ",
|
||||||
|
.HashResult = struct {
|
||||||
|
alg_id: []const u8,
|
||||||
|
alg_version: u16,
|
||||||
|
ln: u6,
|
||||||
|
r: u30,
|
||||||
|
p: u30,
|
||||||
|
salt: BinValue(16),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$v=1$ln=15,r=8,p=1",
|
||||||
|
.HashResult = struct { alg_id: []const u8, alg_version: ?u30, ln: u6, r: u30, p: u30 },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$v=1$c2FsdHNhbHQ$dGVzdHBhc3M",
|
||||||
|
.HashResult = struct {
|
||||||
|
alg_id: []const u8,
|
||||||
|
alg_version: u16,
|
||||||
|
salt: BinValue(16),
|
||||||
|
hash: BinValue(16),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$v=1$c2FsdHNhbHQ",
|
||||||
|
.HashResult = struct { alg_id: []const u8, alg_version: u16, salt: BinValue(16) },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.str = "$scrypt$c2FsdHNhbHQ$dGVzdHBhc3M",
|
||||||
|
.HashResult = struct { alg_id: []const u8, salt: BinValue(16), hash: BinValue(16) },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
inline for (inputs) |input| {
|
||||||
|
const v = try deserialize(input.HashResult, input.str);
|
||||||
|
var buf: [input.str.len]u8 = undefined;
|
||||||
|
const s1 = try serialize(v, &buf);
|
||||||
|
try std.testing.expectEqualSlices(u8, input.str, s1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "phc format - empty input string" {
|
||||||
|
const s = "";
|
||||||
|
const v = deserialize(struct { alg_id: []const u8 }, s);
|
||||||
|
try std.testing.expectError(Error.InvalidEncoding, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "phc format - hash without salt" {
|
||||||
|
const s = "$scrypt";
|
||||||
|
const v = deserialize(struct { alg_id: []const u8, hash: BinValue(16) }, s);
|
||||||
|
try std.testing.expectError(Error.InvalidEncoding, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "phc format - calcSize" {
|
||||||
|
const s = "$scrypt$v=1$ln=15,r=8,p=1$c2FsdHNhbHQ$dGVzdHBhc3M";
|
||||||
|
const v = try deserialize(struct {
|
||||||
|
alg_id: []const u8,
|
||||||
|
alg_version: u16,
|
||||||
|
ln: u6,
|
||||||
|
r: u30,
|
||||||
|
p: u30,
|
||||||
|
salt: BinValue(8),
|
||||||
|
hash: BinValue(8),
|
||||||
|
}, s);
|
||||||
|
try std.testing.expectEqual(calcSize(v), s.len);
|
||||||
|
}
|
||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const utils = std.crypto.utils;
|
const utils = std.crypto.utils;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
|
|||||||
657
lib/std/crypto/scrypt.zig
Normal file
657
lib/std/crypto/scrypt.zig
Normal file
@ -0,0 +1,657 @@
|
|||||||
|
// https://tools.ietf.org/html/rfc7914
|
||||||
|
// https://github.com/golang/crypto/blob/master/scrypt/scrypt.go
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const crypto = std.crypto;
|
||||||
|
const fmt = std.fmt;
|
||||||
|
const io = std.io;
|
||||||
|
const math = std.math;
|
||||||
|
const mem = std.mem;
|
||||||
|
const meta = std.meta;
|
||||||
|
const pwhash = crypto.pwhash;
|
||||||
|
|
||||||
|
const phc_format = @import("phc_encoding.zig");
|
||||||
|
|
||||||
|
const HmacSha256 = crypto.auth.hmac.sha2.HmacSha256;
|
||||||
|
const KdfError = pwhash.KdfError;
|
||||||
|
const HasherError = pwhash.HasherError;
|
||||||
|
const EncodingError = phc_format.Error;
|
||||||
|
const Error = pwhash.Error;
|
||||||
|
|
||||||
|
const max_size = math.maxInt(usize);
|
||||||
|
const max_int = max_size >> 1;
|
||||||
|
const default_salt_len = 32;
|
||||||
|
const default_hash_len = 32;
|
||||||
|
const max_salt_len = 64;
|
||||||
|
const max_hash_len = 64;
|
||||||
|
|
||||||
|
fn blockCopy(dst: []align(16) u32, src: []align(16) const u32, n: usize) void {
|
||||||
|
mem.copy(u32, dst, src[0 .. n * 16]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blockXor(dst: []align(16) u32, src: []align(16) const u32, n: usize) void {
|
||||||
|
for (src[0 .. n * 16]) |v, i| {
|
||||||
|
dst[i] ^= v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QuarterRound = struct { a: usize, b: usize, c: usize, d: u6 };
|
||||||
|
|
||||||
|
fn Rp(a: usize, b: usize, c: usize, d: u6) QuarterRound {
|
||||||
|
return QuarterRound{ .a = a, .b = b, .c = c, .d = d };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn salsa8core(b: *align(16) [16]u32) void {
|
||||||
|
const arx_steps = comptime [_]QuarterRound{
|
||||||
|
Rp(4, 0, 12, 7), Rp(8, 4, 0, 9), Rp(12, 8, 4, 13), Rp(0, 12, 8, 18),
|
||||||
|
Rp(9, 5, 1, 7), Rp(13, 9, 5, 9), Rp(1, 13, 9, 13), Rp(5, 1, 13, 18),
|
||||||
|
Rp(14, 10, 6, 7), Rp(2, 14, 10, 9), Rp(6, 2, 14, 13), Rp(10, 6, 2, 18),
|
||||||
|
Rp(3, 15, 11, 7), Rp(7, 3, 15, 9), Rp(11, 7, 3, 13), Rp(15, 11, 7, 18),
|
||||||
|
Rp(1, 0, 3, 7), Rp(2, 1, 0, 9), Rp(3, 2, 1, 13), Rp(0, 3, 2, 18),
|
||||||
|
Rp(6, 5, 4, 7), Rp(7, 6, 5, 9), Rp(4, 7, 6, 13), Rp(5, 4, 7, 18),
|
||||||
|
Rp(11, 10, 9, 7), Rp(8, 11, 10, 9), Rp(9, 8, 11, 13), Rp(10, 9, 8, 18),
|
||||||
|
Rp(12, 15, 14, 7), Rp(13, 12, 15, 9), Rp(14, 13, 12, 13), Rp(15, 14, 13, 18),
|
||||||
|
};
|
||||||
|
var x = b.*;
|
||||||
|
var j: usize = 0;
|
||||||
|
while (j < 8) : (j += 2) {
|
||||||
|
inline for (arx_steps) |r| {
|
||||||
|
x[r.a] ^= math.rotl(u32, x[r.b] +% x[r.c], r.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = 0;
|
||||||
|
while (j < 16) : (j += 1) {
|
||||||
|
b[j] +%= x[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn salsaXor(tmp: *align(16) [16]u32, in: []align(16) const u32, out: []align(16) u32) void {
|
||||||
|
blockXor(tmp, in, 1);
|
||||||
|
salsa8core(tmp);
|
||||||
|
blockCopy(out, tmp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blockMix(tmp: *align(16) [16]u32, in: []align(16) const u32, out: []align(16) u32, r: u30) void {
|
||||||
|
blockCopy(tmp, in[(2 * r - 1) * 16 ..], 1);
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < 2 * r) : (i += 2) {
|
||||||
|
salsaXor(tmp, in[i * 16 ..], out[i * 8 ..]);
|
||||||
|
salsaXor(tmp, in[i * 16 + 16 ..], out[i * 8 + r * 16 ..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn integerify(b: []align(16) const u32, r: u30) u64 {
|
||||||
|
const j = (2 * r - 1) * 16;
|
||||||
|
return @as(u64, b[j]) | @as(u64, b[j + 1]) << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smix(b: []align(16) u8, r: u30, n: usize, v: []align(16) u32, xy: []align(16) u32) void {
|
||||||
|
var x = xy[0 .. 32 * r];
|
||||||
|
var y = xy[32 * r ..];
|
||||||
|
|
||||||
|
for (x) |*v1, j| {
|
||||||
|
v1.* = mem.readIntSliceLittle(u32, b[4 * j ..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmp: [16]u32 align(16) = undefined;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < n) : (i += 2) {
|
||||||
|
blockCopy(v[i * (32 * r) ..], x, 2 * r);
|
||||||
|
blockMix(&tmp, x, y, r);
|
||||||
|
|
||||||
|
blockCopy(v[(i + 1) * (32 * r) ..], y, 2 * r);
|
||||||
|
blockMix(&tmp, y, x, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < n) : (i += 2) {
|
||||||
|
var j = @intCast(usize, integerify(x, r) & (n - 1));
|
||||||
|
blockXor(x, v[j * (32 * r) ..], 2 * r);
|
||||||
|
blockMix(&tmp, x, y, r);
|
||||||
|
|
||||||
|
j = @intCast(usize, integerify(y, r) & (n - 1));
|
||||||
|
blockXor(y, v[j * (32 * r) ..], 2 * r);
|
||||||
|
blockMix(&tmp, y, x, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x) |v1, j| {
|
||||||
|
mem.writeIntLittle(u32, b[4 * j ..][0..4], v1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Params = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
ln: u6,
|
||||||
|
r: u30,
|
||||||
|
p: u30,
|
||||||
|
|
||||||
|
/// Baseline parameters for interactive logins
|
||||||
|
pub const interactive = Self.fromLimits(524288, 16777216);
|
||||||
|
|
||||||
|
/// Baseline parameters for offline usage
|
||||||
|
pub const sensitive = Self.fromLimits(33554432, 1073741824);
|
||||||
|
|
||||||
|
/// Create parameters from ops and mem limits
|
||||||
|
pub fn fromLimits(ops_limit: u64, mem_limit: usize) Self {
|
||||||
|
const ops = math.max(32768, ops_limit);
|
||||||
|
const r: u30 = 8;
|
||||||
|
if (ops < mem_limit / 32) {
|
||||||
|
const max_n = ops / (r * 4);
|
||||||
|
return Self{ .r = r, .p = 1, .ln = @intCast(u6, math.log2(max_n)) };
|
||||||
|
} else {
|
||||||
|
const max_n = mem_limit / (@intCast(usize, r) * 128);
|
||||||
|
const ln = @intCast(u6, math.log2(max_n));
|
||||||
|
const max_rp = math.min(0x3fffffff, (ops / 4) / (@as(u64, 1) << ln));
|
||||||
|
return Self{ .r = r, .p = @intCast(u30, max_rp / @as(u64, r)), .ln = ln };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Apply scrypt to generate a key from a password.
|
||||||
|
///
|
||||||
|
/// scrypt is defined in RFC 7914.
|
||||||
|
///
|
||||||
|
/// allocator: *mem.Allocator.
|
||||||
|
///
|
||||||
|
/// derived_key: Slice of appropriate size for generated key. Generally 16 or 32 bytes in length.
|
||||||
|
/// May be uninitialized. All bytes will be overwritten.
|
||||||
|
/// Maximum size is `derived_key.len / 32 == 0xffff_ffff`.
|
||||||
|
///
|
||||||
|
/// password: Arbitrary sequence of bytes of any length.
|
||||||
|
///
|
||||||
|
/// salt: Arbitrary sequence of bytes of any length.
|
||||||
|
///
|
||||||
|
/// params: Params.
|
||||||
|
pub fn kdf(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
derived_key: []u8,
|
||||||
|
password: []const u8,
|
||||||
|
salt: []const u8,
|
||||||
|
params: Params,
|
||||||
|
) KdfError!void {
|
||||||
|
if (derived_key.len == 0 or derived_key.len / 32 > 0xffff_ffff) return KdfError.OutputTooLong;
|
||||||
|
if (params.ln == 0 or params.r == 0 or params.p == 0) return KdfError.WeakParameters;
|
||||||
|
|
||||||
|
const n64 = @as(u64, 1) << params.ln;
|
||||||
|
if (n64 > max_size) return KdfError.WeakParameters;
|
||||||
|
const n = @intCast(usize, n64);
|
||||||
|
if (@as(u64, params.r) * @as(u64, params.p) >= 1 << 30 or
|
||||||
|
params.r > max_int / 128 / @as(u64, params.p) or
|
||||||
|
params.r > max_int / 256 or
|
||||||
|
n > max_int / 128 / @as(u64, params.r)) return KdfError.WeakParameters;
|
||||||
|
|
||||||
|
var xy = try allocator.alignedAlloc(u32, 16, 64 * params.r);
|
||||||
|
defer allocator.free(xy);
|
||||||
|
var v = try allocator.alignedAlloc(u32, 16, 32 * n * params.r);
|
||||||
|
defer allocator.free(v);
|
||||||
|
var dk = try allocator.alignedAlloc(u8, 16, params.p * 128 * params.r);
|
||||||
|
defer allocator.free(dk);
|
||||||
|
|
||||||
|
try pwhash.pbkdf2(dk, password, salt, 1, HmacSha256);
|
||||||
|
var i: u32 = 0;
|
||||||
|
while (i < params.p) : (i += 1) {
|
||||||
|
smix(dk[i * 128 * params.r ..], params.r, n, v, xy);
|
||||||
|
}
|
||||||
|
try pwhash.pbkdf2(derived_key, password, dk, 1, HmacSha256);
|
||||||
|
}
|
||||||
|
|
||||||
|
const crypt_format = struct {
|
||||||
|
/// String prefix for scrypt
|
||||||
|
pub const prefix = "$7$";
|
||||||
|
|
||||||
|
/// Standard type for a set of scrypt parameters, with the salt and hash.
|
||||||
|
pub fn HashResult(comptime crypt_max_hash_len: usize) type {
|
||||||
|
return struct {
|
||||||
|
ln: u6,
|
||||||
|
r: u30,
|
||||||
|
p: u30,
|
||||||
|
salt: []const u8,
|
||||||
|
hash: BinValue(crypt_max_hash_len),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Codec = CustomB64Codec("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".*);
|
||||||
|
|
||||||
|
/// A wrapped binary value whose maximum size is `max_len`.
|
||||||
|
///
|
||||||
|
/// This type must be used whenever a binary value is encoded in a PHC-formatted string.
|
||||||
|
/// This includes `salt`, `hash`, and any other binary parameters such as keys.
|
||||||
|
///
|
||||||
|
/// Once initialized, the actual value can be read with the `constSlice()` function.
|
||||||
|
pub fn BinValue(comptime max_len: usize) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
const capacity = max_len;
|
||||||
|
const max_encoded_length = Codec.encodedLen(max_len);
|
||||||
|
|
||||||
|
buf: [max_len]u8 = undefined,
|
||||||
|
len: usize = 0,
|
||||||
|
|
||||||
|
/// Wrap an existing byte slice
|
||||||
|
pub fn fromSlice(slice: []const u8) EncodingError!Self {
|
||||||
|
if (slice.len > capacity) return EncodingError.NoSpaceLeft;
|
||||||
|
var bin_value: Self = undefined;
|
||||||
|
mem.copy(u8, &bin_value.buf, slice);
|
||||||
|
bin_value.len = slice.len;
|
||||||
|
return bin_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the slice containing the actual value.
|
||||||
|
pub fn constSlice(self: Self) []const u8 {
|
||||||
|
return self.buf[0..self.len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fromB64(self: *Self, str: []const u8) !void {
|
||||||
|
const len = Codec.decodedLen(str.len);
|
||||||
|
if (len > self.buf.len) return EncodingError.NoSpaceLeft;
|
||||||
|
try Codec.decode(self.buf[0..len], str);
|
||||||
|
self.len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toB64(self: Self, buf: []u8) ![]const u8 {
|
||||||
|
const value = self.constSlice();
|
||||||
|
const len = Codec.encodedLen(value.len);
|
||||||
|
if (len > buf.len) return EncodingError.NoSpaceLeft;
|
||||||
|
var encoded = buf[0..len];
|
||||||
|
Codec.encode(encoded, value);
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Expand binary data into a salt for the modular crypt format.
|
||||||
|
pub fn saltFromBin(comptime len: usize, salt: [len]u8) [Codec.encodedLen(len)]u8 {
|
||||||
|
var buf: [Codec.encodedLen(len)]u8 = undefined;
|
||||||
|
Codec.encode(&buf, &salt);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize a string into a structure `T` (matching `HashResult`).
|
||||||
|
pub fn deserialize(comptime T: type, str: []const u8) EncodingError!T {
|
||||||
|
var out: T = undefined;
|
||||||
|
|
||||||
|
if (str.len < 16) return EncodingError.InvalidEncoding;
|
||||||
|
if (!mem.eql(u8, prefix, str[0..3])) return EncodingError.InvalidEncoding;
|
||||||
|
out.ln = try Codec.intDecode(u6, str[3..4]);
|
||||||
|
out.r = try Codec.intDecode(u30, str[4..9]);
|
||||||
|
out.p = try Codec.intDecode(u30, str[9..14]);
|
||||||
|
|
||||||
|
var it = mem.split(u8, str[14..], "$");
|
||||||
|
|
||||||
|
const salt = it.next() orelse return EncodingError.InvalidEncoding;
|
||||||
|
if (@hasField(T, "salt")) out.salt = salt;
|
||||||
|
|
||||||
|
const hash_str = it.next() orelse return EncodingError.InvalidEncoding;
|
||||||
|
if (@hasField(T, "hash")) try out.hash.fromB64(hash_str);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize parameters into a string in modular crypt format.
|
||||||
|
pub fn serialize(params: anytype, str: []u8) EncodingError![]const u8 {
|
||||||
|
var buf = io.fixedBufferStream(str);
|
||||||
|
try serializeTo(params, buf.writer());
|
||||||
|
return buf.getWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the number of bytes required to serialize `params`
|
||||||
|
pub fn calcSize(params: anytype) usize {
|
||||||
|
var buf = io.countingWriter(io.null_writer);
|
||||||
|
serializeTo(params, buf.writer()) catch unreachable;
|
||||||
|
return @intCast(usize, buf.bytes_written);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serializeTo(params: anytype, out: anytype) !void {
|
||||||
|
var header: [14]u8 = undefined;
|
||||||
|
mem.copy(u8, header[0..3], prefix);
|
||||||
|
Codec.intEncode(header[3..4], params.ln);
|
||||||
|
Codec.intEncode(header[4..9], params.r);
|
||||||
|
Codec.intEncode(header[9..14], params.p);
|
||||||
|
try out.writeAll(&header);
|
||||||
|
try out.writeAll(params.salt);
|
||||||
|
try out.writeAll("$");
|
||||||
|
var buf: [@TypeOf(params.hash).max_encoded_length]u8 = undefined;
|
||||||
|
const hash_str = try params.hash.toB64(&buf);
|
||||||
|
try out.writeAll(hash_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Custom codec that maps 6 bits into 8 like regular Base64, but uses its own alphabet,
|
||||||
|
/// encodes bits in little-endian, and can also encode integers.
|
||||||
|
fn CustomB64Codec(comptime map: [64]u8) type {
|
||||||
|
return struct {
|
||||||
|
const map64 = map;
|
||||||
|
|
||||||
|
fn encodedLen(len: usize) usize {
|
||||||
|
return (len * 4 + 2) / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decodedLen(len: usize) usize {
|
||||||
|
return len / 4 * 3 + (len % 4) * 3 / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intEncode(dst: []u8, src: anytype) void {
|
||||||
|
var n = src;
|
||||||
|
for (dst) |*x| {
|
||||||
|
x.* = map64[@truncate(u6, n)];
|
||||||
|
n = math.shr(@TypeOf(src), n, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intDecode(comptime T: type, src: *const [(meta.bitCount(T) + 5) / 6]u8) !T {
|
||||||
|
var v: T = 0;
|
||||||
|
for (src) |x, i| {
|
||||||
|
const vi = mem.indexOfScalar(u8, &map64, x) orelse return EncodingError.InvalidEncoding;
|
||||||
|
v |= @intCast(T, vi) << @intCast(math.Log2Int(T), i * 6);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(dst: []u8, src: []const u8) !void {
|
||||||
|
std.debug.assert(dst.len == decodedLen(src.len));
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < src.len / 4) : (i += 1) {
|
||||||
|
mem.writeIntSliceLittle(u24, dst[i * 3 ..], try intDecode(u24, src[i * 4 ..][0..4]));
|
||||||
|
}
|
||||||
|
const leftover = src[i * 4 ..];
|
||||||
|
var v: u24 = 0;
|
||||||
|
for (leftover) |_, j| {
|
||||||
|
v |= @as(u24, try intDecode(u6, leftover[j..][0..1])) << @intCast(u5, j * 6);
|
||||||
|
}
|
||||||
|
for (dst[i * 3 ..]) |*x, j| {
|
||||||
|
x.* = @truncate(u8, v >> @intCast(u5, j * 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode(dst: []u8, src: []const u8) void {
|
||||||
|
std.debug.assert(dst.len == encodedLen(src.len));
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < src.len / 3) : (i += 1) {
|
||||||
|
intEncode(dst[i * 4 ..][0..4], mem.readIntSliceLittle(u24, src[i * 3 ..]));
|
||||||
|
}
|
||||||
|
const leftover = src[i * 3 ..];
|
||||||
|
var v: u24 = 0;
|
||||||
|
for (leftover) |x, j| {
|
||||||
|
v |= @as(u24, x) << @intCast(u5, j * 8);
|
||||||
|
}
|
||||||
|
intEncode(dst[i * 4 ..], v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Hash and verify passwords using the PHC format.
|
||||||
|
const PhcFormatHasher = struct {
|
||||||
|
const alg_id = "scrypt";
|
||||||
|
const BinValue = phc_format.BinValue;
|
||||||
|
|
||||||
|
const HashResult = struct {
|
||||||
|
alg_id: []const u8,
|
||||||
|
ln: u6,
|
||||||
|
r: u30,
|
||||||
|
p: u30,
|
||||||
|
salt: BinValue(max_salt_len),
|
||||||
|
hash: BinValue(max_hash_len),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Return a non-deterministic hash of the password encoded as a PHC-format string
|
||||||
|
pub fn create(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
password: []const u8,
|
||||||
|
params: Params,
|
||||||
|
buf: []u8,
|
||||||
|
) HasherError![]const u8 {
|
||||||
|
var salt: [default_salt_len]u8 = undefined;
|
||||||
|
crypto.random.bytes(&salt);
|
||||||
|
|
||||||
|
var hash: [default_hash_len]u8 = undefined;
|
||||||
|
try kdf(allocator, &hash, password, &salt, params);
|
||||||
|
|
||||||
|
return phc_format.serialize(HashResult{
|
||||||
|
.alg_id = alg_id,
|
||||||
|
.ln = params.ln,
|
||||||
|
.r = params.r,
|
||||||
|
.p = params.p,
|
||||||
|
.salt = try BinValue(max_salt_len).fromSlice(&salt),
|
||||||
|
.hash = try BinValue(max_hash_len).fromSlice(&hash),
|
||||||
|
}, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a password against a PHC-format encoded string
|
||||||
|
pub fn verify(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
str: []const u8,
|
||||||
|
password: []const u8,
|
||||||
|
) HasherError!void {
|
||||||
|
const hash_result = try phc_format.deserialize(HashResult, str);
|
||||||
|
if (!mem.eql(u8, hash_result.alg_id, alg_id)) return HasherError.PasswordVerificationFailed;
|
||||||
|
const params = Params{ .ln = hash_result.ln, .r = hash_result.r, .p = hash_result.p };
|
||||||
|
const expected_hash = hash_result.hash.constSlice();
|
||||||
|
var hash_buf: [max_hash_len]u8 = undefined;
|
||||||
|
if (expected_hash.len > hash_buf.len) return HasherError.InvalidEncoding;
|
||||||
|
var hash = hash_buf[0..expected_hash.len];
|
||||||
|
try kdf(allocator, hash, password, hash_result.salt.constSlice(), params);
|
||||||
|
if (!mem.eql(u8, hash, expected_hash)) return HasherError.PasswordVerificationFailed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Hash and verify passwords using the modular crypt format.
|
||||||
|
const CryptFormatHasher = struct {
|
||||||
|
const BinValue = crypt_format.BinValue;
|
||||||
|
const HashResult = crypt_format.HashResult(max_hash_len);
|
||||||
|
|
||||||
|
/// Length of a string returned by the create() function
|
||||||
|
pub const pwhash_str_length: usize = 101;
|
||||||
|
|
||||||
|
/// Return a non-deterministic hash of the password encoded into the modular crypt format
|
||||||
|
pub fn create(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
password: []const u8,
|
||||||
|
params: Params,
|
||||||
|
buf: []u8,
|
||||||
|
) HasherError![]const u8 {
|
||||||
|
var salt_bin: [default_salt_len]u8 = undefined;
|
||||||
|
crypto.random.bytes(&salt_bin);
|
||||||
|
const salt = crypt_format.saltFromBin(salt_bin.len, salt_bin);
|
||||||
|
|
||||||
|
var hash: [default_hash_len]u8 = undefined;
|
||||||
|
try kdf(allocator, &hash, password, &salt, params);
|
||||||
|
|
||||||
|
return crypt_format.serialize(HashResult{
|
||||||
|
.ln = params.ln,
|
||||||
|
.r = params.r,
|
||||||
|
.p = params.p,
|
||||||
|
.salt = &salt,
|
||||||
|
.hash = try BinValue(max_hash_len).fromSlice(&hash),
|
||||||
|
}, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a password against a string in modular crypt format
|
||||||
|
pub fn verify(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
str: []const u8,
|
||||||
|
password: []const u8,
|
||||||
|
) HasherError!void {
|
||||||
|
const hash_result = try crypt_format.deserialize(HashResult, str);
|
||||||
|
const params = Params{ .ln = hash_result.ln, .r = hash_result.r, .p = hash_result.p };
|
||||||
|
const expected_hash = hash_result.hash.constSlice();
|
||||||
|
var hash_buf: [max_hash_len]u8 = undefined;
|
||||||
|
if (expected_hash.len > hash_buf.len) return HasherError.InvalidEncoding;
|
||||||
|
var hash = hash_buf[0..expected_hash.len];
|
||||||
|
try kdf(allocator, hash, password, hash_result.salt, params);
|
||||||
|
if (!mem.eql(u8, hash, expected_hash)) return HasherError.PasswordVerificationFailed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for hashing a password.
|
||||||
|
pub const HashOptions = struct {
|
||||||
|
allocator: ?*mem.Allocator,
|
||||||
|
params: Params,
|
||||||
|
encoding: pwhash.Encoding,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Compute a hash of a password using the scrypt key derivation function.
|
||||||
|
/// The function returns a string that includes all the parameters required for verification.
|
||||||
|
pub fn strHash(
|
||||||
|
password: []const u8,
|
||||||
|
options: HashOptions,
|
||||||
|
out: []u8,
|
||||||
|
) Error![]const u8 {
|
||||||
|
const allocator = options.allocator orelse return Error.AllocatorRequired;
|
||||||
|
switch (options.encoding) {
|
||||||
|
.phc => return PhcFormatHasher.create(allocator, password, options.params, out),
|
||||||
|
.crypt => return CryptFormatHasher.create(allocator, password, options.params, out),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Options for hash verification.
|
||||||
|
pub const VerifyOptions = struct {
|
||||||
|
allocator: ?*mem.Allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Verify that a previously computed hash is valid for a given password.
|
||||||
|
pub fn strVerify(
|
||||||
|
str: []const u8,
|
||||||
|
password: []const u8,
|
||||||
|
options: VerifyOptions,
|
||||||
|
) Error!void {
|
||||||
|
const allocator = options.allocator orelse return Error.AllocatorRequired;
|
||||||
|
if (mem.startsWith(u8, str, crypt_format.prefix)) {
|
||||||
|
return CryptFormatHasher.verify(allocator, str, password);
|
||||||
|
} else {
|
||||||
|
return PhcFormatHasher.verify(allocator, str, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt kdf" {
|
||||||
|
const password = "testpass";
|
||||||
|
const salt = "saltsalt";
|
||||||
|
|
||||||
|
var dk: [32]u8 = undefined;
|
||||||
|
try kdf(std.testing.allocator, &dk, password, salt, .{ .ln = 15, .r = 8, .p = 1 });
|
||||||
|
|
||||||
|
const hex = "1e0f97c3f6609024022fbe698da29c2fe53ef1087a8e396dc6d5d2a041e886de";
|
||||||
|
var bytes: [hex.len / 2]u8 = undefined;
|
||||||
|
_ = try fmt.hexToBytes(&bytes, hex);
|
||||||
|
|
||||||
|
try std.testing.expectEqualSlices(u8, &bytes, &dk);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt kdf rfc 1" {
|
||||||
|
const password = "";
|
||||||
|
const salt = "";
|
||||||
|
|
||||||
|
var dk: [64]u8 = undefined;
|
||||||
|
try kdf(std.testing.allocator, &dk, password, salt, .{ .ln = 4, .r = 1, .p = 1 });
|
||||||
|
|
||||||
|
const hex = "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906";
|
||||||
|
var bytes: [hex.len / 2]u8 = undefined;
|
||||||
|
_ = try fmt.hexToBytes(&bytes, hex);
|
||||||
|
|
||||||
|
try std.testing.expectEqualSlices(u8, &bytes, &dk);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt kdf rfc 2" {
|
||||||
|
const password = "password";
|
||||||
|
const salt = "NaCl";
|
||||||
|
|
||||||
|
var dk: [64]u8 = undefined;
|
||||||
|
try kdf(std.testing.allocator, &dk, password, salt, .{ .ln = 10, .r = 8, .p = 16 });
|
||||||
|
|
||||||
|
const hex = "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640";
|
||||||
|
var bytes: [hex.len / 2]u8 = undefined;
|
||||||
|
_ = try fmt.hexToBytes(&bytes, hex);
|
||||||
|
|
||||||
|
try std.testing.expectEqualSlices(u8, &bytes, &dk);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt kdf rfc 3" {
|
||||||
|
const password = "pleaseletmein";
|
||||||
|
const salt = "SodiumChloride";
|
||||||
|
|
||||||
|
var dk: [64]u8 = undefined;
|
||||||
|
try kdf(std.testing.allocator, &dk, password, salt, .{ .ln = 14, .r = 8, .p = 1 });
|
||||||
|
|
||||||
|
const hex = "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887";
|
||||||
|
var bytes: [hex.len / 2]u8 = undefined;
|
||||||
|
_ = try fmt.hexToBytes(&bytes, hex);
|
||||||
|
|
||||||
|
try std.testing.expectEqualSlices(u8, &bytes, &dk);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt kdf rfc 4" {
|
||||||
|
// skip slow test
|
||||||
|
if (true) {
|
||||||
|
return error.SkipZigTest;
|
||||||
|
}
|
||||||
|
|
||||||
|
const password = "pleaseletmein";
|
||||||
|
const salt = "SodiumChloride";
|
||||||
|
|
||||||
|
var dk: [64]u8 = undefined;
|
||||||
|
try kdf(std.testing.allocator, &dk, password, salt, .{ .ln = 20, .r = 8, .p = 1 });
|
||||||
|
|
||||||
|
const hex = "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4";
|
||||||
|
var bytes: [hex.len / 2]u8 = undefined;
|
||||||
|
_ = try fmt.hexToBytes(&bytes, hex);
|
||||||
|
|
||||||
|
try std.testing.expectEqualSlices(u8, &bytes, &dk);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt password hashing (crypt format)" {
|
||||||
|
const str = "$7$A6....1....TrXs5Zk6s8sWHpQgWDIXTR8kUU3s6Jc3s.DtdS8M2i4$a4ik5hGDN7foMuHOW.cp.CtX01UyCeO0.JAG.AHPpx5";
|
||||||
|
const password = "Y0!?iQa9M%5ekffW(`";
|
||||||
|
try CryptFormatHasher.verify(std.testing.allocator, str, password);
|
||||||
|
|
||||||
|
const params = Params.interactive;
|
||||||
|
var buf: [CryptFormatHasher.pwhash_str_length]u8 = undefined;
|
||||||
|
const str2 = try CryptFormatHasher.create(std.testing.allocator, password, params, &buf);
|
||||||
|
try CryptFormatHasher.verify(std.testing.allocator, str2, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt strHash and strVerify" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const password = "testpass";
|
||||||
|
const verify_options = VerifyOptions{ .allocator = alloc };
|
||||||
|
var buf: [128]u8 = undefined;
|
||||||
|
|
||||||
|
const s = try strHash(
|
||||||
|
password,
|
||||||
|
HashOptions{ .allocator = alloc, .params = Params.interactive, .encoding = .crypt },
|
||||||
|
&buf,
|
||||||
|
);
|
||||||
|
try strVerify(s, password, verify_options);
|
||||||
|
|
||||||
|
const s1 = try strHash(
|
||||||
|
password,
|
||||||
|
HashOptions{ .allocator = alloc, .params = Params.interactive, .encoding = .phc },
|
||||||
|
&buf,
|
||||||
|
);
|
||||||
|
try strVerify(s1, password, verify_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt unix-scrypt" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
// https://gitlab.com/jas/scrypt-unix-crypt/blob/master/unix-scrypt.txt
|
||||||
|
{
|
||||||
|
const str = "$7$C6..../....SodiumChloride$kBGj9fHznVYFQMEn/qDCfrDevf9YDtcDdKvEqHJLV8D";
|
||||||
|
const password = "pleaseletmein";
|
||||||
|
try strVerify(str, password, .{ .allocator = alloc });
|
||||||
|
}
|
||||||
|
// one of the libsodium test vectors
|
||||||
|
{
|
||||||
|
const str = "$7$B6....1....75gBMAGwfFWZqBdyF3WdTQnWdUsuTiWjG1fF9c1jiSD$tc8RoB3.Em3/zNgMLWo2u00oGIoTyJv4fl3Fl8Tix72";
|
||||||
|
const password = "^T5H$JYt39n%K*j:W]!1s?vg!:jGi]Ax?..l7[p0v:1jHTpla9;]bUN;?bWyCbtqg nrDFal+Jxl3,2`#^tFSu%v_+7iYse8-cCkNf!tD=KrW)";
|
||||||
|
try strVerify(str, password, .{ .allocator = alloc });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "scrypt crypt format" {
|
||||||
|
const str = "$7$C6..../....SodiumChloride$kBGj9fHznVYFQMEn/qDCfrDevf9YDtcDdKvEqHJLV8D";
|
||||||
|
const params = try crypt_format.deserialize(crypt_format.HashResult(32), str);
|
||||||
|
var buf: [str.len]u8 = undefined;
|
||||||
|
const s1 = try crypt_format.serialize(params, &buf);
|
||||||
|
try std.testing.expectEqualStrings(s1, str);
|
||||||
|
}
|
||||||
@ -1,8 +1,3 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright (c) 2015-2021 Zig Contributors
|
|
||||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
|
||||||
// The MIT license requires this copyright notice to be included in all copies
|
|
||||||
// and substantial portions of the software.
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user