authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-19 19:01:28-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-19 19:01:28-04:00
log04c25efe112e374facaf1bc8b58bbdb6999a39e3
tree66a70b185ad8e44a69c8be27dd7dbc23425b040c
parent4ffab5b85f03f63a7e724698482f8497cacc7212
parent381c6a38b145665a22440f7aa816f0ddd9b70ee5
signaturelock-open Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into copy-elision-3


20 files changed, 604 insertions(+), 277 deletions(-)

CMakeLists.txt+1
......@@ -479,6 +479,7 @@ set(ZIG_STD_FILES
479479 "crypto.zig"
480480 "crypto/blake2.zig"
481481 "crypto/chacha20.zig"
482 "crypto/gimli.zig"
482483 "crypto/hmac.zig"
483484 "crypto/md5.zig"
484485 "crypto/poly1305.zig"
doc/langref.html.in+1-1
......@@ -4927,7 +4927,7 @@ test "peer type resolution: *const T and ?*T" {
49274927 <li>The {#link|Integers#} {#syntax#}u0{#endsyntax#} and {#syntax#}i0{#endsyntax#}.</li>
49284928 <li>{#link|Arrays#} and {#link|Vectors#} with len 0, or with an element type that is a zero bit type.</li>
49294929 <li>An {#link|enum#} with only 1 tag.</li>
4930 <li>An {#link|struct#} with all fields being zero bit types.</li>
4930 <li>A {#link|struct#} with all fields being zero bit types.</li>
49314931 <li>A {#link|union#} with only 1 field which is a zero bit type.</li>
49324932 <li>{#link|Pointers to Zero Bit Types#} are themselves zero bit types.</li>
49334933 </ul>
src/buffer.hpp+2
......@@ -27,11 +27,13 @@ Buf *buf_sprintf(const char *format, ...)
2727Buf *buf_vprintf(const char *format, va_list ap);
2828
2929static inline size_t buf_len(Buf *buf) {
30 assert(buf);
3031 assert(buf->list.length);
3132 return buf->list.length - 1;
3233}
3334
3435static inline char *buf_ptr(Buf *buf) {
36 assert(buf);
3537 assert(buf->list.length);
3638 return buf->list.items;
3739}
src/codegen.cpp+2-1
......@@ -8732,6 +8732,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
87328732
87338733 Termination term;
87348734 ZigList<const char *> args = {};
8735 args.append(buf_ptr(self_exe_path));
87358736 args.append("cc");
87368737
87378738 Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path));
......@@ -8750,7 +8751,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
87508751 if (g->verbose_cc) {
87518752 print_zig_cc_cmd("zig", &args);
87528753 }
8753 os_spawn_process(buf_ptr(self_exe_path), args, &term);
8754 os_spawn_process(args, &term);
87548755 if (term.how != TerminationIdClean || term.code != 0) {
87558756 fprintf(stderr, "\nThe following command failed:\n");
87568757 print_zig_cc_cmd(buf_ptr(self_exe_path), &args);
src/ir.cpp+6-3
......@@ -18046,7 +18046,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1804618046 case ZigTypeIdPromise:
1804718047 case ZigTypeIdVector:
1804818048 {
18049 if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
18049 ResolveStatus needed_status = (align_bytes == 0) ?
18050 ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;
18051 if ((err = type_resolve(ira->codegen, child_type, needed_status)))
1805018052 return ira->codegen->invalid_instruction;
1805118053 ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
1805218054 is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0, is_allow_zero);
......@@ -19901,10 +19903,11 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
1990119903 true, false, PtrLenUnknown,
1990219904 0, 0, 0, false);
1990319905 fn_decl_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
19904 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
19906 if (fn_node->is_extern && fn_node->lib_name != nullptr && buf_len(fn_node->lib_name) > 0) {
1990519907 fn_decl_fields[6].data.x_optional = create_const_vals(1);
1990619908 ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);
19907 init_const_slice(ira->codegen, fn_decl_fields[6].data.x_optional, lib_name, 0, buf_len(fn_node->lib_name), true);
19909 init_const_slice(ira->codegen, fn_decl_fields[6].data.x_optional, lib_name, 0,
19910 buf_len(fn_node->lib_name), true);
1990819911 } else {
1990919912 fn_decl_fields[6].data.x_optional = nullptr;
1991019913 }
src/libc_installation.cpp+4-2
......@@ -153,6 +153,7 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b
153153 const char *cc_exe = getenv("CC");
154154 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;
155155 ZigList<const char *> args = {};
156 args.append(cc_exe);
156157 args.append("-E");
157158 args.append("-Wp,-v");
158159 args.append("-xc");
......@@ -166,7 +167,7 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b
166167 Buf *out_stderr = buf_alloc();
167168 Buf *out_stdout = buf_alloc();
168169 Error err;
169 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
170 if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) {
170171 if (verbose) {
171172 fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));
172173 }
......@@ -277,12 +278,13 @@ Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirnam
277278 const char *cc_exe = getenv("CC");
278279 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;
279280 ZigList<const char *> args = {};
281 args.append(cc_exe);
280282 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
281283 Termination term;
282284 Buf *out_stderr = buf_alloc();
283285 Buf *out_stdout = buf_alloc();
284286 Error err;
285 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
287 if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) {
286288 if (err == ErrorFileNotFound)
287289 return ErrorNoCCompilerInstalled;
288290 if (verbose) {
src/link.cpp+2-1
......@@ -1721,10 +1721,11 @@ void codegen_link(CodeGen *g) {
17211721 if (g->system_linker_hack && g->zig_target->os == OsMacOSX) {
17221722 Termination term;
17231723 ZigList<const char *> args = {};
1724 args.append("ld");
17241725 for (size_t i = 1; i < lj.args.length; i += 1) {
17251726 args.append(lj.args.at(i));
17261727 }
1727 os_spawn_process("ld", args, &term);
1728 os_spawn_process(args, &term);
17281729 if (term.how != TerminationIdClean || term.code != 0) {
17291730 exit(1);
17301731 }
src/main.cpp+12-16
......@@ -467,6 +467,7 @@ int main(int argc, char **argv) {
467467 init_all_targets();
468468
469469 ZigList<const char *> args = {0};
470 args.append(NULL); // placeholder
470471 args.append(zig_exe_path);
471472 args.append(NULL); // placeholder
472473 args.append(NULL); // placeholder
......@@ -525,8 +526,8 @@ int main(int argc, char **argv) {
525526 g->enable_time_report = timing_info;
526527 codegen_set_out_name(g, buf_create_from_str("build"));
527528
528 args.items[1] = buf_ptr(&build_file_dirname);
529 args.items[2] = buf_ptr(&full_cache_dir);
529 args.items[2] = buf_ptr(&build_file_dirname);
530 args.items[3] = buf_ptr(&full_cache_dir);
530531
531532 bool build_file_exists;
532533 if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {
......@@ -580,12 +581,14 @@ int main(int argc, char **argv) {
580581 codegen_build_and_link(g);
581582
582583 Termination term;
583 os_spawn_process(buf_ptr(&g->output_file_path), args, &term);
584 args.items[0] = buf_ptr(&g->output_file_path);
585 os_spawn_process(args, &term);
584586 if (term.how != TerminationIdClean || term.code != 0) {
585587 fprintf(stderr, "\nBuild failed. The following command failed:\n");
586 fprintf(stderr, "%s", buf_ptr(&g->output_file_path));
588 const char *prefix = "";
587589 for (size_t i = 0; i < args.length; i += 1) {
588 fprintf(stderr, " %s", args.at(i));
590 fprintf(stderr, "%s%s", prefix, args.at(i));
591 prefix = " ";
589592 }
590593 fprintf(stderr, "\n");
591594 }
......@@ -1161,7 +1164,7 @@ int main(int argc, char **argv) {
11611164
11621165 args.pop();
11631166 Termination term;
1164 os_spawn_process(exec_path, args, &term);
1167 os_spawn_process(args, &term);
11651168 return term.code;
11661169 } else if (cmd == CmdBuild) {
11671170 if (g->enable_cache) {
......@@ -1213,17 +1216,10 @@ int main(int argc, char **argv) {
12131216 }
12141217
12151218 Termination term;
1216 if (test_exec_args.length > 0) {
1217 ZigList<const char *> rest_args = {0};
1218 for (size_t i = 1; i < test_exec_args.length; i += 1) {
1219 rest_args.append(test_exec_args.at(i));
1220 }
1221 os_spawn_process(test_exec_args.items[0], rest_args, &term);
1222 } else {
1223 ZigList<const char *> no_args = {0};
1224 os_spawn_process(buf_ptr(test_exe_path), no_args, &term);
1219 if (test_exec_args.length == 0) {
1220 test_exec_args.append(buf_ptr(test_exe_path));
12251221 }
1226
1222 os_spawn_process(test_exec_args, &term);
12271223 if (term.how != TerminationIdClean || term.code != 0) {
12281224 fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
12291225 fprintf(stderr, "%s\n", buf_ptr(test_exe_path));
src/os.cpp+27-29
......@@ -105,16 +105,15 @@ static void populate_termination(Termination *term, int status) {
105105 }
106106}
107107
108static void os_spawn_process_posix(const char *exe, ZigList<const char *> &args, Termination *term) {
109 const char **argv = allocate<const char *>(args.length + 2);
110 argv[0] = exe;
111 argv[args.length + 1] = nullptr;
108static void os_spawn_process_posix(ZigList<const char *> &args, Termination *term) {
109 const char **argv = allocate<const char *>(args.length + 1);
112110 for (size_t i = 0; i < args.length; i += 1) {
113 argv[i + 1] = args.at(i);
111 argv[i] = args.at(i);
114112 }
113 argv[args.length] = nullptr;
115114
116115 pid_t pid;
117 int rc = posix_spawnp(&pid, exe, nullptr, nullptr, const_cast<char *const*>(argv), environ);
116 int rc = posix_spawnp(&pid, args.at(0), nullptr, nullptr, const_cast<char *const*>(argv), environ);
118117 if (rc != 0) {
119118 zig_panic("posix_spawn failed: %s", strerror(rc));
120119 }
......@@ -126,16 +125,14 @@ static void os_spawn_process_posix(const char *exe, ZigList<const char *> &args,
126125#endif
127126
128127#if defined(ZIG_OS_WINDOWS)
129static void os_windows_create_command_line(Buf *command_line, const char *exe, ZigList<const char *> &args) {
130 buf_resize(command_line, 0);
131
132 buf_append_char(command_line, '\"');
133 buf_append_str(command_line, exe);
134 buf_append_char(command_line, '\"');
135128
129static void os_windows_create_command_line(Buf *command_line, ZigList<const char *> &args) {
130 buf_resize(command_line, 0);
131 char *prefix = "\"";
136132 for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {
137 buf_append_str(command_line, " \"");
138133 const char *arg = args.at(arg_i);
134 buf_append_str(command_line, prefix);
135 prefix = " \"";
139136 size_t arg_len = strlen(arg);
140137 for (size_t c_i = 0; c_i < arg_len; c_i += 1) {
141138 if (arg[c_i] == '\"') {
......@@ -147,14 +144,15 @@ static void os_windows_create_command_line(Buf *command_line, const char *exe, Z
147144 }
148145}
149146
150static void os_spawn_process_windows(const char *exe, ZigList<const char *> &args, Termination *term) {
147static void os_spawn_process_windows(ZigList<const char *> &args, Termination *term) {
151148 Buf command_line = BUF_INIT;
152 os_windows_create_command_line(&command_line, exe, args);
149 os_windows_create_command_line(&command_line, args);
153150
154151 PROCESS_INFORMATION piProcInfo = {0};
155152 STARTUPINFO siStartInfo = {0};
156153 siStartInfo.cb = sizeof(STARTUPINFO);
157154
155 const char *exe = args.at(0);
158156 BOOL success = CreateProcessA(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,
159157 &siStartInfo, &piProcInfo);
160158
......@@ -173,11 +171,11 @@ static void os_spawn_process_windows(const char *exe, ZigList<const char *> &arg
173171}
174172#endif
175173
176void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term) {
174void os_spawn_process(ZigList<const char *> &args, Termination *term) {
177175#if defined(ZIG_OS_WINDOWS)
178 os_spawn_process_windows(exe, args, term);
176 os_spawn_process_windows(args, term);
179177#elif defined(ZIG_OS_POSIX)
180 os_spawn_process_posix(exe, args, term);
178 os_spawn_process_posix(args, term);
181179#else
182180#error "missing os_spawn_process implementation"
183181#endif
......@@ -785,7 +783,7 @@ Error os_file_exists(Buf *full_path, bool *result) {
785783}
786784
787785#if defined(ZIG_OS_POSIX)
788static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args,
786static Error os_exec_process_posix(ZigList<const char *> &args,
789787 Termination *term, Buf *out_stderr, Buf *out_stdout)
790788{
791789 int stdin_pipe[2];
......@@ -817,13 +815,12 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args,
817815 if (dup2(stderr_pipe[1], STDERR_FILENO) == -1)
818816 zig_panic("dup2 failed");
819817
820 const char **argv = allocate<const char *>(args.length + 2);
821 argv[0] = exe;
822 argv[args.length + 1] = nullptr;
818 const char **argv = allocate<const char *>(args.length + 1);
819 argv[args.length] = nullptr;
823820 for (size_t i = 0; i < args.length; i += 1) {
824 argv[i + 1] = args.at(i);
821 argv[i] = args.at(i);
825822 }
826 execvp(exe, const_cast<char * const *>(argv));
823 execvp(argv[0], const_cast<char * const *>(argv));
827824 Error report_err = ErrorUnexpected;
828825 if (errno == ENOENT) {
829826 report_err = ErrorFileNotFound;
......@@ -874,11 +871,11 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args,
874871// LocalFree(messageBuffer);
875872//}
876873
877static Error os_exec_process_windows(const char *exe, ZigList<const char *> &args,
874static Error os_exec_process_windows(ZigList<const char *> &args,
878875 Termination *term, Buf *out_stderr, Buf *out_stdout)
879876{
880877 Buf command_line = BUF_INIT;
881 os_windows_create_command_line(&command_line, exe, args);
878 os_windows_create_command_line(&command_line, args);
882879
883880 HANDLE g_hChildStd_IN_Rd = NULL;
884881 HANDLE g_hChildStd_IN_Wr = NULL;
......@@ -925,6 +922,7 @@ static Error os_exec_process_windows(const char *exe, ZigList<const char *> &arg
925922 siStartInfo.hStdInput = g_hChildStd_IN_Rd;
926923 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
927924
925 const char *exe = args.at(0);
928926 BOOL success = CreateProcess(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,
929927 &siStartInfo, &piProcInfo);
930928
......@@ -1005,13 +1003,13 @@ Error os_execv(const char *exe, const char **argv) {
10051003#endif
10061004}
10071005
1008Error os_exec_process(const char *exe, ZigList<const char *> &args,
1006Error os_exec_process(ZigList<const char *> &args,
10091007 Termination *term, Buf *out_stderr, Buf *out_stdout)
10101008{
10111009#if defined(ZIG_OS_WINDOWS)
1012 return os_exec_process_windows(exe, args, term, out_stderr, out_stdout);
1010 return os_exec_process_windows(args, term, out_stderr, out_stdout);
10131011#elif defined(ZIG_OS_POSIX)
1014 return os_exec_process_posix(exe, args, term, out_stderr, out_stdout);
1012 return os_exec_process_posix(args, term, out_stderr, out_stdout);
10151013#else
10161014#error "missing os_exec_process implementation"
10171015#endif
src/os.hpp+2-2
......@@ -100,8 +100,8 @@ struct OsFileAttr {
100100
101101int os_init(void);
102102
103void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term);
104Error os_exec_process(const char *exe, ZigList<const char *> &args,
103void os_spawn_process(ZigList<const char *> &args, Termination *term);
104Error os_exec_process(ZigList<const char *> &args,
105105 Termination *term, Buf *out_stderr, Buf *out_stdout);
106106Error os_execv(const char *exe, const char **argv);
107107
std/atomic/queue.zig+20-1
......@@ -100,7 +100,7 @@ pub fn Queue(comptime T: type) type {
100100 pub fn isEmpty(self: *Self) bool {
101101 const held = self.mutex.acquire();
102102 defer held.release();
103 return self.head != null;
103 return self.head == null;
104104 }
105105
106106 pub fn dump(self: *Self) void {
......@@ -172,12 +172,14 @@ test "std.atomic.Queue" {
172172 };
173173
174174 if (builtin.single_threaded) {
175 expect(context.queue.isEmpty());
175176 {
176177 var i: usize = 0;
177178 while (i < put_thread_count) : (i += 1) {
178179 expect(startPuts(&context) == 0);
179180 }
180181 }
182 expect(!context.queue.isEmpty());
181183 context.puts_done = 1;
182184 {
183185 var i: usize = 0;
......@@ -185,7 +187,10 @@ test "std.atomic.Queue" {
185187 expect(startGets(&context) == 0);
186188 }
187189 }
190 expect(context.queue.isEmpty());
188191 } else {
192 expect(context.queue.isEmpty());
193
189194 var putters: [put_thread_count]*std.Thread = undefined;
190195 for (putters) |*t| {
191196 t.* = try std.Thread.spawn(&context, startPuts);
......@@ -200,6 +205,8 @@ test "std.atomic.Queue" {
200205 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
201206 for (getters) |t|
202207 t.wait();
208
209 expect(context.queue.isEmpty());
203210 }
204211
205212 if (context.put_sum != context.get_sum) {
......@@ -250,6 +257,7 @@ fn startGets(ctx: *Context) u8 {
250257
251258test "std.atomic.Queue single-threaded" {
252259 var queue = Queue(i32).init();
260 expect(queue.isEmpty());
253261
254262 var node_0 = Queue(i32).Node{
255263 .data = 0,
......@@ -257,6 +265,7 @@ test "std.atomic.Queue single-threaded" {
257265 .prev = undefined,
258266 };
259267 queue.put(&node_0);
268 expect(!queue.isEmpty());
260269
261270 var node_1 = Queue(i32).Node{
262271 .data = 1,
......@@ -264,8 +273,10 @@ test "std.atomic.Queue single-threaded" {
264273 .prev = undefined,
265274 };
266275 queue.put(&node_1);
276 expect(!queue.isEmpty());
267277
268278 expect(queue.get().?.data == 0);
279 expect(!queue.isEmpty());
269280
270281 var node_2 = Queue(i32).Node{
271282 .data = 2,
......@@ -273,6 +284,7 @@ test "std.atomic.Queue single-threaded" {
273284 .prev = undefined,
274285 };
275286 queue.put(&node_2);
287 expect(!queue.isEmpty());
276288
277289 var node_3 = Queue(i32).Node{
278290 .data = 3,
......@@ -280,10 +292,13 @@ test "std.atomic.Queue single-threaded" {
280292 .prev = undefined,
281293 };
282294 queue.put(&node_3);
295 expect(!queue.isEmpty());
283296
284297 expect(queue.get().?.data == 1);
298 expect(!queue.isEmpty());
285299
286300 expect(queue.get().?.data == 2);
301 expect(!queue.isEmpty());
287302
288303 var node_4 = Queue(i32).Node{
289304 .data = 4,
......@@ -291,13 +306,17 @@ test "std.atomic.Queue single-threaded" {
291306 .prev = undefined,
292307 };
293308 queue.put(&node_4);
309 expect(!queue.isEmpty());
294310
295311 expect(queue.get().?.data == 3);
296312 node_3.next = null;
313 expect(!queue.isEmpty());
297314
298315 expect(queue.get().?.data == 4);
316 expect(queue.isEmpty());
299317
300318 expect(queue.get() == null);
319 expect(queue.isEmpty());
301320}
302321
303322test "std.atomic.Queue dump" {
std/child_process.zig+22-15
......@@ -543,25 +543,32 @@ pub const ChildProcess = struct {
543543
544544 const PATH = try process.getEnvVarOwned(self.allocator, "PATH");
545545 defer self.allocator.free(PATH);
546 const PATHEXT = try process.getEnvVarOwned(self.allocator, "PATHEXT");
547 defer self.allocator.free(PATHEXT);
546548
547549 var it = mem.tokenize(PATH, ";");
548 while (it.next()) |search_path| {
549 const joined_path = try fs.path.join(self.allocator, [_][]const u8{ search_path, app_name });
550 defer self.allocator.free(joined_path);
551
552 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);
553 defer self.allocator.free(joined_path_w);
554
555 if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
556 break;
557 } else |err| if (err == error.FileNotFound) {
558 continue;
559 } else {
560 return err;
550 retry: while (it.next()) |search_path| {
551 var ext_it = mem.tokenize(PATHEXT, ";");
552 while (ext_it.next()) |app_ext| {
553 const app_basename = try mem.concat(self.allocator, u8, [_][]const u8{app_name[0..app_name.len - 1], app_ext});
554 defer self.allocator.free(app_basename);
555
556 const joined_path = try fs.path.join(self.allocator, [_][]const u8{ search_path, app_basename });
557 defer self.allocator.free(joined_path);
558
559 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);
560 defer self.allocator.free(joined_path_w);
561
562 if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
563 break :retry;
564 } else |err| switch (err) {
565 error.FileNotFound => { continue; },
566 error.AccessDenied => { continue; },
567 else => { return err; },
568 }
561569 }
562570 } else {
563 // Every other error would have been returned earlier.
564 return error.FileNotFound;
571 return no_path_err; // return the original error
565572 }
566573 };
567574
std/crypto.zig+3
......@@ -13,6 +13,8 @@ pub const Sha3_256 = sha3.Sha3_256;
1313pub const Sha3_384 = sha3.Sha3_384;
1414pub const Sha3_512 = sha3.Sha3_512;
1515
16pub const gimli = @import("crypto/gimli.zig");
17
1618const blake2 = @import("crypto/blake2.zig");
1719pub const Blake2s224 = blake2.Blake2s224;
1820pub const Blake2s256 = blake2.Blake2s256;
......@@ -38,6 +40,7 @@ pub const randomBytes = std.os.getrandom;
3840test "crypto" {
3941 _ = @import("crypto/blake2.zig");
4042 _ = @import("crypto/chacha20.zig");
43 _ = @import("crypto/gimli.zig");
4144 _ = @import("crypto/hmac.zig");
4245 _ = @import("crypto/md5.zig");
4346 _ = @import("crypto/poly1305.zig");
std/crypto/gimli.zig created+168
......@@ -0,0 +1,168 @@
1// Gimli is a 384-bit permutation designed to achieve high security with high
2// performance across a broad range of platforms, including 64-bit Intel/AMD
3// server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
4// microcontrollers, 8-bit AVR microcontrollers, FPGAs, ASICs without
5// side-channel protection, and ASICs with side-channel protection.
6//
7// https://gimli.cr.yp.to/
8// https://csrc.nist.gov/CSRC/media/Projects/Lightweight-Cryptography/documents/round-1/spec-doc/gimli-spec.pdf
9
10const std = @import("../std.zig");
11const mem = std.mem;
12const math = std.math;
13const debug = std.debug;
14const assert = std.debug.assert;
15const testing = std.testing;
16const htest = @import("test.zig");
17
18pub const State = struct {
19 pub const BLOCKBYTES = 48;
20 pub const RATE = 16;
21
22 // TODO: https://github.com/ziglang/zig/issues/2673#issuecomment-501763017
23 data: [BLOCKBYTES / 4]u32,
24
25 const Self = @This();
26
27 pub fn toSlice(self: *Self) []u8 {
28 return @sliceToBytes(self.data[0..]);
29 }
30
31 pub fn toSliceConst(self: *Self) []const u8 {
32 return @sliceToBytes(self.data[0..]);
33 }
34
35 pub fn permute(self: *Self) void {
36 const state = &self.data;
37 var round = u32(24);
38 while (round > 0) : (round -= 1) {
39 var column = usize(0);
40 while (column < 4) : (column += 1) {
41 const x = math.rotl(u32, state[column], 24);
42 const y = math.rotl(u32, state[4 + column], 9);
43 const z = state[8 + column];
44 state[8 + column] = ((x ^ (z << 1)) ^ ((y & z) << 2));
45 state[4 + column] = ((y ^ x) ^ ((x | z) << 1));
46 state[column] = ((z ^ y) ^ ((x & y) << 3));
47 }
48 switch (round & 3) {
49 0 => {
50 mem.swap(u32, &state[0], &state[1]);
51 mem.swap(u32, &state[2], &state[3]);
52 state[0] ^= round | 0x9e377900;
53 },
54 2 => {
55 mem.swap(u32, &state[0], &state[2]);
56 mem.swap(u32, &state[1], &state[3]);
57 },
58 else => {},
59 }
60 }
61 }
62
63 pub fn squeeze(self: *Self, out: []u8) void {
64 var i = usize(0);
65 while (i + RATE <= out.len) : (i += RATE) {
66 self.permute();
67 mem.copy(u8, out[i..], self.toSliceConst()[0..RATE]);
68 }
69 const leftover = out.len - i;
70 if (leftover != 0) {
71 self.permute();
72 mem.copy(u8, out[i..], self.toSliceConst()[0..leftover]);
73 }
74 }
75};
76
77test "permute" {
78 // test vector from gimli-20170627
79 var state = State{
80 .data = blk: {
81 var input: [12]u32 = undefined;
82 var i = u32(0);
83 while (i < 12) : (i += 1) {
84 input[i] = i * i * i + i *% 0x9e3779b9;
85 }
86 testing.expectEqualSlices(u32, input, [_]u32{
87 0x00000000, 0x9e3779ba, 0x3c6ef37a, 0xdaa66d46,
88 0x78dde724, 0x1715611a, 0xb54cdb2e, 0x53845566,
89 0xf1bbcfc8, 0x8ff34a5a, 0x2e2ac522, 0xcc624026,
90 });
91 break :blk input;
92 },
93 };
94 state.permute();
95 testing.expectEqualSlices(u32, state.data, [_]u32{
96 0xba11c85a, 0x91bad119, 0x380ce880, 0xd24c2c68,
97 0x3eceffea, 0x277a921c, 0x4f73a0bd, 0xda5a9cd8,
98 0x84b673f0, 0x34e52ff7, 0x9e2bef49, 0xf41bb8d6,
99 });
100}
101
102pub const Hash = struct {
103 state: State,
104 buf_off: usize,
105
106 const Self = @This();
107
108 pub fn init() Self {
109 return Self{
110 .state = State{
111 .data = [_]u32{0} ** (State.BLOCKBYTES / 4),
112 },
113 .buf_off = 0,
114 };
115 }
116
117 /// Also known as 'absorb'
118 pub fn update(self: *Self, data: []const u8) void {
119 const buf = self.state.toSlice();
120 var in = data;
121 while (in.len > 0) {
122 var left = State.RATE - self.buf_off;
123 if (left == 0) {
124 self.state.permute();
125 self.buf_off = 0;
126 left = State.RATE;
127 }
128 const ps = math.min(in.len, left);
129 for (buf[self.buf_off .. self.buf_off + ps]) |*p, i| {
130 p.* ^= in[i];
131 }
132 self.buf_off += ps;
133 in = in[ps..];
134 }
135 }
136
137 /// Finish the current hashing operation, writing the hash to `out`
138 ///
139 /// From 4.9 "Application to hashing"
140 /// By default, Gimli-Hash provides a fixed-length output of 32 bytes
141 /// (the concatenation of two 16-byte blocks). However, Gimli-Hash can
142 /// be used as an “extendable one-way function” (XOF).
143 pub fn final(self: *Self, out: []u8) void {
144 const buf = self.state.toSlice();
145
146 // XOR 1 into the next byte of the state
147 buf[self.buf_off] ^= 1;
148 // XOR 1 into the last byte of the state, position 47.
149 buf[buf.len - 1] ^= 1;
150
151 self.state.squeeze(out);
152 }
153};
154
155pub fn hash(out: []u8, in: []const u8) void {
156 var st = Hash.init();
157 st.update(in);
158 st.final(out);
159}
160
161test "hash" {
162 // a test vector (30) from NIST KAT submission.
163 var msg: [58 / 2]u8 = undefined;
164 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
165 var md: [32]u8 = undefined;
166 hash(&md, msg);
167 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", md);
168}
std/fmt.zig+254-197
......@@ -13,7 +13,13 @@ pub const default_max_depth = 3;
1313/// Renders fmt string with args, calling output with slices of bytes.
1414/// If `output` returns an error, the error is returned from `format` and
1515/// `output` is not called again.
16pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
16pub fn format(
17 context: var,
18 comptime Errors: type,
19 output: fn (@typeOf(context), []const u8) Errors!void,
20 comptime fmt: []const u8,
21 args: ...,
22) Errors!void {
1723 const State = enum {
1824 Start,
1925 OpenBrace,
......@@ -28,7 +34,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
2834
2935 inline for (fmt) |c, i| {
3036 switch (state) {
31 State.Start => switch (c) {
37 .Start => switch (c) {
3238 '{' => {
3339 if (start_index < i) {
3440 try output(context, fmt[start_index..i]);
......@@ -45,7 +51,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
4551 },
4652 else => {},
4753 },
48 State.OpenBrace => switch (c) {
54 .OpenBrace => switch (c) {
4955 '{' => {
5056 state = State.Start;
5157 start_index = i;
......@@ -61,14 +67,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
6167 state = State.FormatString;
6268 },
6369 },
64 State.CloseBrace => switch (c) {
70 .CloseBrace => switch (c) {
6571 '}' => {
6672 state = State.Start;
6773 start_index = i;
6874 },
6975 else => @compileError("Single '}' encountered in format string"),
7076 },
71 State.FormatString => switch (c) {
77 .FormatString => switch (c) {
7278 '}' => {
7379 const s = start_index + 1;
7480 try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth);
......@@ -78,7 +84,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
7884 },
7985 else => {},
8086 },
81 State.Pointer => switch (c) {
87 .Pointer => switch (c) {
8288 '}' => {
8389 try output(context, @typeName(@typeOf(args[next_arg]).Child));
8490 try output(context, "@");
......@@ -114,88 +120,93 @@ pub fn formatType(
114120) Errors!void {
115121 const T = @typeOf(value);
116122 switch (@typeInfo(T)) {
117 builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
123 .ComptimeInt, .Int, .Float => {
118124 return formatValue(value, fmt, context, Errors, output);
119125 },
120 builtin.TypeId.Void => {
126 .Void => {
121127 return output(context, "void");
122128 },
123 builtin.TypeId.Bool => {
129 .Bool => {
124130 return output(context, if (value) "true" else "false");
125131 },
126 builtin.TypeId.Optional => {
132 .Optional => {
127133 if (value) |payload| {
128134 return formatType(payload, fmt, context, Errors, output, max_depth);
129135 } else {
130136 return output(context, "null");
131137 }
132138 },
133 builtin.TypeId.ErrorUnion => {
139 .ErrorUnion => {
134140 if (value) |payload| {
135141 return formatType(payload, fmt, context, Errors, output, max_depth);
136142 } else |err| {
137143 return formatType(err, fmt, context, Errors, output, max_depth);
138144 }
139145 },
140 builtin.TypeId.ErrorSet => {
146 .ErrorSet => {
141147 try output(context, "error.");
142148 return output(context, @errorName(value));
143149 },
144 builtin.TypeId.Promise => {
150 .Promise => {
145151 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
146152 },
147 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
148 if (comptime std.meta.trait.hasFn("format")(T)) return value.format(fmt, context, Errors, output);
153 .Enum => {
154 if (comptime std.meta.trait.hasFn("format")(T)) {
155 return value.format(fmt, context, Errors, output);
156 }
149157
150158 try output(context, @typeName(T));
151 switch (comptime @typeId(T)) {
152 builtin.TypeId.Enum => {
153 try output(context, ".");
154 try formatType(@tagName(value), "", context, Errors, output, max_depth);
155 return;
156 },
157 builtin.TypeId.Struct => {
158 if (max_depth == 0) {
159 return output(context, "{ ... }");
160 }
161 comptime var field_i = 0;
162 inline while (field_i < @memberCount(T)) : (field_i += 1) {
163 if (field_i == 0) {
164 try output(context, "{ .");
165 } else {
166 try output(context, ", .");
167 }
168 try output(context, @memberName(T, field_i));
169 try output(context, " = ");
170 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);
171 }
172 try output(context, " }");
173 },
174 builtin.TypeId.Union => {
175 if (max_depth == 0) {
176 return output(context, "{ ... }");
177 }
178 const info = @typeInfo(T).Union;
179 if (info.tag_type) |UnionTagType| {
180 try output(context, "{ .");
181 try output(context, @tagName(UnionTagType(value)));
182 try output(context, " = ");
183 inline for (info.fields) |u_field| {
184 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
185 try formatType(@field(value, u_field.name), "", context, Errors, output, max_depth - 1);
186 }
187 }
188 try output(context, " }");
189 } else {
190 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
159 try output(context, ".");
160 return formatType(@tagName(value), "", context, Errors, output, max_depth);
161 },
162 .Union => {
163 if (comptime std.meta.trait.hasFn("format")(T)) {
164 return value.format(fmt, context, Errors, output);
165 }
166
167 try output(context, @typeName(T));
168 if (max_depth == 0) {
169 return output(context, "{ ... }");
170 }
171 const info = @typeInfo(T).Union;
172 if (info.tag_type) |UnionTagType| {
173 try output(context, "{ .");
174 try output(context, @tagName(UnionTagType(value)));
175 try output(context, " = ");
176 inline for (info.fields) |u_field| {
177 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
178 try formatType(@field(value, u_field.name), "", context, Errors, output, max_depth - 1);
191179 }
192 },
193 else => unreachable,
180 }
181 try output(context, " }");
182 } else {
183 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
194184 }
195 return;
196185 },
197 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
198 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
186 .Struct => {
187 if (comptime std.meta.trait.hasFn("format")(T)) {
188 return value.format(fmt, context, Errors, output);
189 }
190
191 try output(context, @typeName(T));
192 if (max_depth == 0) {
193 return output(context, "{ ... }");
194 }
195 comptime var field_i = 0;
196 inline while (field_i < @memberCount(T)) : (field_i += 1) {
197 if (field_i == 0) {
198 try output(context, "{ .");
199 } else {
200 try output(context, ", .");
201 }
202 try output(context, @memberName(T, field_i));
203 try output(context, " = ");
204 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);
205 }
206 try output(context, " }");
207 },
208 .Pointer => |ptr_info| switch (ptr_info.size) {
209 .One => switch (@typeInfo(ptr_info.child)) {
199210 builtin.TypeId.Array => |info| {
200211 if (info.child == u8) {
201212 return formatText(value, fmt, context, Errors, output);
......@@ -207,7 +218,7 @@ pub fn formatType(
207218 },
208219 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
209220 },
210 builtin.TypeInfo.Pointer.Size.Many => {
221 .Many => {
211222 if (ptr_info.child == u8) {
212223 if (fmt.len > 0 and fmt[0] == 's') {
213224 const len = mem.len(u8, value);
......@@ -216,7 +227,7 @@ pub fn formatType(
216227 }
217228 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
218229 },
219 builtin.TypeInfo.Pointer.Size.Slice => {
230 .Slice => {
220231 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
221232 return formatText(value, fmt, context, Errors, output);
222233 }
......@@ -225,17 +236,17 @@ pub fn formatType(
225236 }
226237 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));
227238 },
228 builtin.TypeInfo.Pointer.Size.C => {
239 .C => {
229240 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
230241 },
231242 },
232 builtin.TypeId.Array => |info| {
243 .Array => |info| {
233244 if (info.child == u8) {
234245 return formatText(value, fmt, context, Errors, output);
235246 }
236247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
237248 },
238 builtin.TypeId.Fn => {
249 .Fn => {
239250 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
240251 },
241252 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
......@@ -249,24 +260,24 @@ fn formatValue(
249260 comptime Errors: type,
250261 output: fn (@typeOf(context), []const u8) Errors!void,
251262) Errors!void {
252 if (fmt.len > 0) {
253 if (fmt[0] == 'B') {
254 comptime var width: ?usize = null;
255 if (fmt.len > 1) {
256 if (fmt[1] == 'i') {
257 if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
258 return formatBytes(value, width, 1024, context, Errors, output);
263 if (fmt.len > 0 and fmt[0] == 'B') {
264 comptime var width: ?usize = null;
265 if (fmt.len > 1) {
266 if (fmt[1] == 'i') {
267 if (fmt.len > 2) {
268 width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
259269 }
260 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
270 return formatBytes(value, width, 1024, context, Errors, output);
261271 }
262 return formatBytes(value, width, 1000, context, Errors, output);
272 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
263273 }
274 return formatBytes(value, width, 1000, context, Errors, output);
264275 }
265276
266277 const T = @typeOf(value);
267278 switch (@typeId(T)) {
268 builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
269 builtin.TypeId.Int, builtin.TypeId.ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),
279 .Float => return formatFloatValue(value, fmt, context, Errors, output),
280 .Int, .ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),
270281 else => comptime unreachable,
271282 }
272283}
......@@ -797,7 +808,7 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
797808 }
798809}
799810
800test "fmt.parseInt" {
811test "parseInt" {
801812 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
802813 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
803814 testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
......@@ -828,7 +839,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
828839 return x;
829840}
830841
831test "fmt.parseUnsigned" {
842test "parseUnsigned" {
832843 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
833844 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
834845 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
......@@ -913,7 +924,7 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
913924 size.* += bytes.len;
914925}
915926
916test "buf print int" {
927test "bufPrintInt" {
917928 var buffer: [100]u8 = undefined;
918929 const buf = buffer[0..];
919930 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
......@@ -949,7 +960,7 @@ test "parse unsigned comptime" {
949960 }
950961}
951962
952test "fmt.format" {
963test "fmt.optional" {
953964 {
954965 const value: ?i32 = 1234;
955966 try testFmt("optional: 1234\n", "optional: {}\n", value);
......@@ -958,6 +969,9 @@ test "fmt.format" {
958969 const value: ?i32 = null;
959970 try testFmt("optional: null\n", "optional: {}\n", value);
960971 }
972}
973
974test "fmt.error" {
961975 {
962976 const value: anyerror!i32 = 1234;
963977 try testFmt("error union: 1234\n", "error union: {}\n", value);
......@@ -966,10 +980,16 @@ test "fmt.format" {
966980 const value: anyerror!i32 = error.InvalidChar;
967981 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
968982 }
983}
984
985test "fmt.int.small" {
969986 {
970987 const value: u3 = 0b101;
971988 try testFmt("u3: 5\n", "u3: {}\n", value);
972989 }
990}
991
992test "fmt.int.specifier" {
973993 {
974994 const value: u8 = 'a';
975995 try testFmt("u8: a\n", "u8: {c}\n", value);
......@@ -978,6 +998,9 @@ test "fmt.format" {
978998 const value: u8 = 0b1100;
979999 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
9801000 }
1001}
1002
1003test "fmt.buffer" {
9811004 {
9821005 var buf1: [32]u8 = undefined;
9831006 var context = BufPrintContext{ .remaining = buf1[0..] };
......@@ -995,6 +1018,9 @@ test "fmt.format" {
9951018 res = buf1[0 .. buf1.len - context.remaining.len];
9961019 testing.expect(mem.eql(u8, res, "1100"));
9971020 }
1021}
1022
1023test "fmt.array" {
9981024 {
9991025 const value: [3]u8 = "abc";
10001026 try testFmt("array: abc\n", "array: {}\n", value);
......@@ -1007,6 +1033,9 @@ test "fmt.format" {
10071033 &value,
10081034 );
10091035 }
1036}
1037
1038test "fmt.slice" {
10101039 {
10111040 const value: []const u8 = "abc";
10121041 try testFmt("slice: abc\n", "slice: {}\n", value);
......@@ -1015,6 +1044,12 @@ test "fmt.format" {
10151044 const value = @intToPtr([*]const []const u8, 0xdeadbeef)[0..0];
10161045 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);
10171046 }
1047
1048 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
1049 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1050}
1051
1052test "fmt.pointer" {
10181053 {
10191054 const value = @intToPtr(*i32, 0xdeadbeef);
10201055 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
......@@ -1028,12 +1063,19 @@ test "fmt.format" {
10281063 const value = @intToPtr(fn () void, 0xdeadbeef);
10291064 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
10301065 }
1031 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
1032 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1066}
1067
1068test "fmt.cstr" {
10331069 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
10341070 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
1071}
1072
1073test "fmt.filesize" {
10351074 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
10361075 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
1076}
1077
1078test "fmt.struct" {
10371079 {
10381080 const Struct = struct {
10391081 field: u8,
......@@ -1050,15 +1092,19 @@ test "fmt.format" {
10501092 const value = Struct{ .a = 0, .b = 1 };
10511093 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
10521094 }
1053 {
1054 const Enum = enum {
1055 One,
1056 Two,
1057 };
1058 const value = Enum.Two;
1059 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
1060 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1061 }
1095}
1096
1097test "fmt.enum" {
1098 const Enum = enum {
1099 One,
1100 Two,
1101 };
1102 const value = Enum.Two;
1103 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
1104 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1105}
1106
1107test "fmt.float.scientific" {
10621108 {
10631109 var buf1: [32]u8 = undefined;
10641110 const value: f32 = 1.34;
......@@ -1088,6 +1134,9 @@ test "fmt.format" {
10881134 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
10891135 }
10901136 }
1137}
1138
1139test "fmt.float.scientific.precision" {
10911140 {
10921141 var buf1: [32]u8 = undefined;
10931142 const value: f64 = 1.409706e-42;
......@@ -1114,6 +1163,9 @@ test "fmt.format" {
11141163 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
11151164 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
11161165 }
1166}
1167
1168test "fmt.float.special" {
11171169 {
11181170 var buf1: [32]u8 = undefined;
11191171 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
......@@ -1136,6 +1188,9 @@ test "fmt.format" {
11361188 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
11371189 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
11381190 }
1191}
1192
1193test "fmt.float.decimal" {
11391194 {
11401195 var buf1: [64]u8 = undefined;
11411196 const value: f64 = 1.52314e+29;
......@@ -1216,7 +1271,9 @@ test "fmt.format" {
12161271 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
12171272 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
12181273 }
1219 // libc checks
1274}
1275
1276test "fmt.float.libc.sanity" {
12201277 {
12211278 var buf1: [32]u8 = undefined;
12221279 const value: f64 = f64(@bitCast(f32, u32(916964781)));
......@@ -1267,127 +1324,127 @@ test "fmt.format" {
12671324 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
12681325 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
12691326 }
1270 //custom type format
1271 {
1272 const Vec2 = struct {
1273 const SelfType = @This();
1274 x: f32,
1275 y: f32,
1276
1277 pub fn format(
1278 self: SelfType,
1279 comptime fmt: []const u8,
1280 context: var,
1281 comptime Errors: type,
1282 output: fn (@typeOf(context), []const u8) Errors!void,
1283 ) Errors!void {
1284 switch (fmt.len) {
1285 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1286 1 => switch (fmt[0]) {
1287 //point format
1288 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1289 //dimension format
1290 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1291 else => unreachable,
1292 },
1327}
1328
1329test "fmt.custom" {
1330 const Vec2 = struct {
1331 const SelfType = @This();
1332 x: f32,
1333 y: f32,
1334
1335 pub fn format(
1336 self: SelfType,
1337 comptime fmt: []const u8,
1338 context: var,
1339 comptime Errors: type,
1340 output: fn (@typeOf(context), []const u8) Errors!void,
1341 ) Errors!void {
1342 switch (fmt.len) {
1343 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1344 1 => switch (fmt[0]) {
1345 //point format
1346 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1347 //dimension format
1348 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
12931349 else => unreachable,
1294 }
1350 },
1351 else => unreachable,
12951352 }
1296 };
1353 }
1354 };
12971355
1298 var buf1: [32]u8 = undefined;
1299 var value = Vec2{
1300 .x = 10.2,
1301 .y = 2.22,
1302 };
1303 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1304 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
1356 var buf1: [32]u8 = undefined;
1357 var value = Vec2{
1358 .x = 10.2,
1359 .y = 2.22,
1360 };
1361 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1362 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
13051363
1306 // same thing but not passing a pointer
1307 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1308 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1309 }
1310 //struct format
1311 {
1312 const S = struct {
1313 a: u32,
1314 b: anyerror,
1315 };
1364 // same thing but not passing a pointer
1365 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1366 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1367}
13161368
1317 const inst = S{
1318 .a = 456,
1319 .b = error.Unused,
1320 };
1369test "fmt.struct" {
1370 const S = struct {
1371 a: u32,
1372 b: anyerror,
1373 };
13211374
1322 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1323 }
1324 //union format
1325 {
1326 const TU = union(enum) {
1327 float: f32,
1328 int: u32,
1329 };
1375 const inst = S{
1376 .a = 456,
1377 .b = error.Unused,
1378 };
13301379
1331 const UU = union {
1332 float: f32,
1333 int: u32,
1334 };
1380 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1381}
13351382
1336 const EU = extern union {
1337 float: f32,
1338 int: u32,
1339 };
1383test "fmt.union" {
1384 const TU = union(enum) {
1385 float: f32,
1386 int: u32,
1387 };
13401388
1341 const tu_inst = TU{ .int = 123 };
1342 const uu_inst = UU{ .int = 456 };
1343 const eu_inst = EU{ .float = 321.123 };
1389 const UU = union {
1390 float: f32,
1391 int: u32,
1392 };
13441393
1345 try testFmt("TU{ .int = 123 }", "{}", tu_inst);
1394 const EU = extern union {
1395 float: f32,
1396 int: u32,
1397 };
13461398
1347 var buf: [100]u8 = undefined;
1348 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
1349 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
1399 const tu_inst = TU{ .int = 123 };
1400 const uu_inst = UU{ .int = 456 };
1401 const eu_inst = EU{ .float = 321.123 };
13501402
1351 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1352 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1353 }
1354 //enum format
1355 {
1356 const E = enum {
1357 One,
1358 Two,
1359 Three,
1360 };
1403 try testFmt("TU{ .int = 123 }", "{}", tu_inst);
13611404
1362 const inst = E.Two;
1405 var buf: [100]u8 = undefined;
1406 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
1407 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
13631408
1364 try testFmt("E.Two", "{}", inst);
1365 }
1366 //self-referential struct format
1367 {
1368 const S = struct {
1369 const SelfType = @This();
1370 a: ?*SelfType,
1371 };
1409 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1410 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1411}
13721412
1373 var inst = S{
1374 .a = null,
1375 };
1376 inst.a = &inst;
1413test "fmt.enum" {
1414 const E = enum {
1415 One,
1416 Two,
1417 Three,
1418 };
13771419
1378 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
1379 }
1380 //print bytes as hex
1381 {
1382 const some_bytes = "\xCA\xFE\xBA\xBE";
1383 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1384 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
1385 //Test Slices
1386 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
1387 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
1388 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1389 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
1390 }
1420 const inst = E.Two;
1421
1422 try testFmt("E.Two", "{}", inst);
1423}
1424
1425test "fmt.struct.self-referential" {
1426 const S = struct {
1427 const SelfType = @This();
1428 a: ?*SelfType,
1429 };
1430
1431 var inst = S{
1432 .a = null,
1433 };
1434 inst.a = &inst;
1435
1436 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
1437}
1438
1439test "fmt.bytes.hex" {
1440 const some_bytes = "\xCA\xFE\xBA\xBE";
1441 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1442 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
1443 //Test Slices
1444 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
1445 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
1446 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1447 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
13911448}
13921449
13931450fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
std/hash_map.zig+5-5
......@@ -564,12 +564,12 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
564564 },
565565
566566 builtin.TypeId.Float => |info| {
567 return autoHash(@bitCast(@IntType(false, info.bits), key), rng);
567 return autoHash(@bitCast(@IntType(false, info.bits), key), rng, HashInt);
568568 },
569 builtin.TypeId.Bool => return autoHash(@boolToInt(key), rng),
570 builtin.TypeId.Enum => return autoHash(@enumToInt(key), rng),
571 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng),
572 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng),
569 builtin.TypeId.Bool => return autoHash(@boolToInt(key), rng, HashInt),
570 builtin.TypeId.Enum => return autoHash(@enumToInt(key), rng, HashInt),
571 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng, HashInt),
572 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng, HashInt),
573573
574574 builtin.TypeId.BoundFn,
575575 builtin.TypeId.ComptimeFloat,
std/mem.zig+37
......@@ -996,6 +996,43 @@ test "mem.join" {
996996 testing.expect(eql(u8, try join(a, ",", [_][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c"));
997997}
998998
999/// Copies each T from slices into a new slice that exactly holds all the elements.
1000pub fn concat(allocator: *Allocator, comptime T: type, slices: []const []const T) ![]T {
1001 if (slices.len == 0) return (([*]T)(undefined))[0..0];
1002
1003 const total_len = blk: {
1004 var sum: usize = 0;
1005 for (slices) |slice| {
1006 sum += slice.len;
1007 }
1008 break :blk sum;
1009 };
1010
1011 const buf = try allocator.alloc(T, total_len);
1012 errdefer allocator.free(buf);
1013
1014 var buf_index: usize = 0;
1015 for (slices) |slice| {
1016 copy(T, buf[buf_index..], slice);
1017 buf_index += slice.len;
1018 }
1019
1020 // No need for shrink since buf is exactly the correct size.
1021 return buf;
1022}
1023
1024test "concat" {
1025 var buf: [1024]u8 = undefined;
1026 const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
1027 testing.expect(eql(u8, try concat(a, u8, [_][]const u8{ "abc", "def", "ghi" }), "abcdefghi"));
1028 testing.expect(eql(u32, try concat(a, u32, [_][]const u32{
1029 [_]u32{ 0, 1 },
1030 [_]u32{ 2, 3, 4 },
1031 [_]u32{},
1032 [_]u32{5},
1033 }), [_]u32{ 0, 1, 2, 3, 4, 5 }));
1034}
1035
9991036test "testStringEquality" {
10001037 testing.expect(eql(u8, "abcd", "abcd"));
10011038 testing.expect(!eql(u8, "abcdef", "abZdef"));
std/os/windows.zig+2
......@@ -632,6 +632,7 @@ pub fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) G
632632
633633pub const CreateProcessError = error{
634634 FileNotFound,
635 AccessDenied,
635636 InvalidName,
636637 Unexpected,
637638};
......@@ -663,6 +664,7 @@ pub fn CreateProcessW(
663664 switch (kernel32.GetLastError()) {
664665 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
665666 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
667 ERROR.ACCESS_DENIED => return error.AccessDenied,
666668 ERROR.INVALID_PARAMETER => unreachable,
667669 ERROR.INVALID_NAME => return error.InvalidName,
668670 else => |err| return unexpectedError(err),
test/stage1/behavior/slice.zig+11
......@@ -54,3 +54,14 @@ test "comptime slices are disambiguated" {
5454 expect(sliceSum([_]u8{ 1, 2 }) == 3);
5555 expect(sliceSum([_]u8{ 3, 4 }) == 7);
5656}
57
58test "slice type with custom alignment" {
59 const LazilyResolvedType = struct {
60 anything: i32,
61 };
62 var slice: []align(32) LazilyResolvedType = undefined;
63 var array: [10]LazilyResolvedType align(32) = undefined;
64 slice = &array;
65 slice[1].anything = 42;
66 expect(array[1].anything == 42);
67}
test/stage1/behavior/type_info.zig+23-4
......@@ -1,7 +1,9 @@
1const expect = @import("std").testing.expect;
2const mem = @import("std").mem;
3const TypeInfo = @import("builtin").TypeInfo;
4const TypeId = @import("builtin").TypeId;
1const std = @import("std");
2const expect = std.testing.expect;
3const mem = std.mem;
4const builtin = @import("builtin");
5const TypeInfo = builtin.TypeInfo;
6const TypeId = builtin.TypeId;
57
68test "type info: tag type, void info" {
79 testBasic();
......@@ -317,3 +319,20 @@ test "type info: TypeId -> TypeInfo impl cast" {
317319 _ = passTypeInfo(TypeId.Void);
318320 _ = comptime passTypeInfo(TypeId.Void);
319321}
322
323test "type info: extern fns with and without lib names" {
324 const S = struct {
325 extern fn bar1() void;
326 extern "cool" fn bar2() void;
327 };
328 const info = @typeInfo(S);
329 comptime {
330 for (info.Struct.decls) |decl| {
331 if (std.mem.eql(u8, decl.name, "bar1")) {
332 expect(decl.data.Fn.lib_name == null);
333 } else {
334 std.testing.expectEqual(([]const u8)("cool"), decl.data.Fn.lib_name.?);
335 }
336 }
337 }
338}