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...@@ -479,6 +479,7 @@ set(ZIG_STD_FILES
479 "crypto.zig"479 "crypto.zig"
480 "crypto/blake2.zig"480 "crypto/blake2.zig"
481 "crypto/chacha20.zig"481 "crypto/chacha20.zig"
482 "crypto/gimli.zig"
482 "crypto/hmac.zig"483 "crypto/hmac.zig"
483 "crypto/md5.zig"484 "crypto/md5.zig"
484 "crypto/poly1305.zig"485 "crypto/poly1305.zig"
doc/langref.html.in+1-1
...@@ -4927,7 +4927,7 @@ test "peer type resolution: *const T and ?*T" {...@@ -4927,7 +4927,7 @@ test "peer type resolution: *const T and ?*T" {
4927 <li>The {#link|Integers#} {#syntax#}u0{#endsyntax#} and {#syntax#}i0{#endsyntax#}.</li>4927 <li>The {#link|Integers#} {#syntax#}u0{#endsyntax#} and {#syntax#}i0{#endsyntax#}.</li>
4928 <li>{#link|Arrays#} and {#link|Vectors#} with len 0, or with an element type that is a zero bit type.</li>4928 <li>{#link|Arrays#} and {#link|Vectors#} with len 0, or with an element type that is a zero bit type.</li>
4929 <li>An {#link|enum#} with only 1 tag.</li>4929 <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>
4931 <li>A {#link|union#} with only 1 field which is a zero bit type.</li>4931 <li>A {#link|union#} with only 1 field which is a zero bit type.</li>
4932 <li>{#link|Pointers to Zero Bit Types#} are themselves zero bit types.</li>4932 <li>{#link|Pointers to Zero Bit Types#} are themselves zero bit types.</li>
4933 </ul>4933 </ul>
src/buffer.hpp+2
...@@ -27,11 +27,13 @@ Buf *buf_sprintf(const char *format, ...)...@@ -27,11 +27,13 @@ Buf *buf_sprintf(const char *format, ...)
27Buf *buf_vprintf(const char *format, va_list ap);27Buf *buf_vprintf(const char *format, va_list ap);
2828
29static inline size_t buf_len(Buf *buf) {29static inline size_t buf_len(Buf *buf) {
30 assert(buf);
30 assert(buf->list.length);31 assert(buf->list.length);
31 return buf->list.length - 1;32 return buf->list.length - 1;
32}33}
3334
34static inline char *buf_ptr(Buf *buf) {35static inline char *buf_ptr(Buf *buf) {
36 assert(buf);
35 assert(buf->list.length);37 assert(buf->list.length);
36 return buf->list.items;38 return buf->list.items;
37}39}
src/codegen.cpp+2-1
...@@ -8732,6 +8732,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {...@@ -8732,6 +8732,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
87328732
8733 Termination term;8733 Termination term;
8734 ZigList<const char *> args = {};8734 ZigList<const char *> args = {};
8735 args.append(buf_ptr(self_exe_path));
8735 args.append("cc");8736 args.append("cc");
87368737
8737 Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path));8738 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) {...@@ -8750,7 +8751,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
8750 if (g->verbose_cc) {8751 if (g->verbose_cc) {
8751 print_zig_cc_cmd("zig", &args);8752 print_zig_cc_cmd("zig", &args);
8752 }8753 }
8753 os_spawn_process(buf_ptr(self_exe_path), args, &term);8754 os_spawn_process(args, &term);
8754 if (term.how != TerminationIdClean || term.code != 0) {8755 if (term.how != TerminationIdClean || term.code != 0) {
8755 fprintf(stderr, "\nThe following command failed:\n");8756 fprintf(stderr, "\nThe following command failed:\n");
8756 print_zig_cc_cmd(buf_ptr(self_exe_path), &args);8757 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,...@@ -18046,7 +18046,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
18046 case ZigTypeIdPromise:18046 case ZigTypeIdPromise:
18047 case ZigTypeIdVector:18047 case ZigTypeIdVector:
18048 {18048 {
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)))
18050 return ira->codegen->invalid_instruction;18052 return ira->codegen->invalid_instruction;
18051 ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,18053 ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
18052 is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0, is_allow_zero);18054 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...@@ -19901,10 +19903,11 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
19901 true, false, PtrLenUnknown,19903 true, false, PtrLenUnknown,
19902 0, 0, 0, false);19904 0, 0, 0, false);
19903 fn_decl_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));19905 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) {
19905 fn_decl_fields[6].data.x_optional = create_const_vals(1);19907 fn_decl_fields[6].data.x_optional = create_const_vals(1);
19906 ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);19908 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);
19908 } else {19911 } else {
19909 fn_decl_fields[6].data.x_optional = nullptr;19912 fn_decl_fields[6].data.x_optional = nullptr;
19910 }19913 }
src/libc_installation.cpp+4-2
...@@ -153,6 +153,7 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b...@@ -153,6 +153,7 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b
153 const char *cc_exe = getenv("CC");153 const char *cc_exe = getenv("CC");
154 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;154 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;
155 ZigList<const char *> args = {};155 ZigList<const char *> args = {};
156 args.append(cc_exe);
156 args.append("-E");157 args.append("-E");
157 args.append("-Wp,-v");158 args.append("-Wp,-v");
158 args.append("-xc");159 args.append("-xc");
...@@ -166,7 +167,7 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b...@@ -166,7 +167,7 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b
166 Buf *out_stderr = buf_alloc();167 Buf *out_stderr = buf_alloc();
167 Buf *out_stdout = buf_alloc();168 Buf *out_stdout = buf_alloc();
168 Error err;169 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))) {
170 if (verbose) {171 if (verbose) {
171 fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));172 fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));
172 }173 }
...@@ -277,12 +278,13 @@ Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirnam...@@ -277,12 +278,13 @@ Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirnam
277 const char *cc_exe = getenv("CC");278 const char *cc_exe = getenv("CC");
278 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;279 cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe;
279 ZigList<const char *> args = {};280 ZigList<const char *> args = {};
281 args.append(cc_exe);
280 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));282 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
281 Termination term;283 Termination term;
282 Buf *out_stderr = buf_alloc();284 Buf *out_stderr = buf_alloc();
283 Buf *out_stdout = buf_alloc();285 Buf *out_stdout = buf_alloc();
284 Error err;286 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))) {
286 if (err == ErrorFileNotFound)288 if (err == ErrorFileNotFound)
287 return ErrorNoCCompilerInstalled;289 return ErrorNoCCompilerInstalled;
288 if (verbose) {290 if (verbose) {
src/link.cpp+2-1
...@@ -1721,10 +1721,11 @@ void codegen_link(CodeGen *g) {...@@ -1721,10 +1721,11 @@ void codegen_link(CodeGen *g) {
1721 if (g->system_linker_hack && g->zig_target->os == OsMacOSX) {1721 if (g->system_linker_hack && g->zig_target->os == OsMacOSX) {
1722 Termination term;1722 Termination term;
1723 ZigList<const char *> args = {};1723 ZigList<const char *> args = {};
1724 args.append("ld");
1724 for (size_t i = 1; i < lj.args.length; i += 1) {1725 for (size_t i = 1; i < lj.args.length; i += 1) {
1725 args.append(lj.args.at(i));1726 args.append(lj.args.at(i));
1726 }1727 }
1727 os_spawn_process("ld", args, &term);1728 os_spawn_process(args, &term);
1728 if (term.how != TerminationIdClean || term.code != 0) {1729 if (term.how != TerminationIdClean || term.code != 0) {
1729 exit(1);1730 exit(1);
1730 }1731 }
src/main.cpp+12-16
...@@ -467,6 +467,7 @@ int main(int argc, char **argv) {...@@ -467,6 +467,7 @@ int main(int argc, char **argv) {
467 init_all_targets();467 init_all_targets();
468468
469 ZigList<const char *> args = {0};469 ZigList<const char *> args = {0};
470 args.append(NULL); // placeholder
470 args.append(zig_exe_path);471 args.append(zig_exe_path);
471 args.append(NULL); // placeholder472 args.append(NULL); // placeholder
472 args.append(NULL); // placeholder473 args.append(NULL); // placeholder
...@@ -525,8 +526,8 @@ int main(int argc, char **argv) {...@@ -525,8 +526,8 @@ int main(int argc, char **argv) {
525 g->enable_time_report = timing_info;526 g->enable_time_report = timing_info;
526 codegen_set_out_name(g, buf_create_from_str("build"));527 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(&build_file_dirname);
529 args.items[2] = buf_ptr(&full_cache_dir);530 args.items[3] = buf_ptr(&full_cache_dir);
530531
531 bool build_file_exists;532 bool build_file_exists;
532 if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {533 if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {
...@@ -580,12 +581,14 @@ int main(int argc, char **argv) {...@@ -580,12 +581,14 @@ int main(int argc, char **argv) {
580 codegen_build_and_link(g);581 codegen_build_and_link(g);
581582
582 Termination term;583 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);
584 if (term.how != TerminationIdClean || term.code != 0) {586 if (term.how != TerminationIdClean || term.code != 0) {
585 fprintf(stderr, "\nBuild failed. The following command failed:\n");587 fprintf(stderr, "\nBuild failed. The following command failed:\n");
586 fprintf(stderr, "%s", buf_ptr(&g->output_file_path));588 const char *prefix = "";
587 for (size_t i = 0; i < args.length; i += 1) {589 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 = " ";
589 }592 }
590 fprintf(stderr, "\n");593 fprintf(stderr, "\n");
591 }594 }
...@@ -1161,7 +1164,7 @@ int main(int argc, char **argv) {...@@ -1161,7 +1164,7 @@ int main(int argc, char **argv) {
11611164
1162 args.pop();1165 args.pop();
1163 Termination term;1166 Termination term;
1164 os_spawn_process(exec_path, args, &term);1167 os_spawn_process(args, &term);
1165 return term.code;1168 return term.code;
1166 } else if (cmd == CmdBuild) {1169 } else if (cmd == CmdBuild) {
1167 if (g->enable_cache) {1170 if (g->enable_cache) {
...@@ -1213,17 +1216,10 @@ int main(int argc, char **argv) {...@@ -1213,17 +1216,10 @@ int main(int argc, char **argv) {
1213 }1216 }
12141217
1215 Termination term;1218 Termination term;
1216 if (test_exec_args.length > 0) {1219 if (test_exec_args.length == 0) {
1217 ZigList<const char *> rest_args = {0};1220 test_exec_args.append(buf_ptr(test_exe_path));
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);
1225 }1221 }
12261222 os_spawn_process(test_exec_args, &term);
1227 if (term.how != TerminationIdClean || term.code != 0) {1223 if (term.how != TerminationIdClean || term.code != 0) {
1228 fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");1224 fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
1229 fprintf(stderr, "%s\n", buf_ptr(test_exe_path));1225 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) {...@@ -105,16 +105,15 @@ static void populate_termination(Termination *term, int status) {
105 }105 }
106}106}
107107
108static void os_spawn_process_posix(const char *exe, ZigList<const char *> &args, Termination *term) {108static void os_spawn_process_posix(ZigList<const char *> &args, Termination *term) {
109 const char **argv = allocate<const char *>(args.length + 2);109 const char **argv = allocate<const char *>(args.length + 1);
110 argv[0] = exe;
111 argv[args.length + 1] = nullptr;
112 for (size_t i = 0; i < args.length; i += 1) {110 for (size_t i = 0; i < args.length; i += 1) {
113 argv[i + 1] = args.at(i);111 argv[i] = args.at(i);
114 }112 }
113 argv[args.length] = nullptr;
115114
116 pid_t pid;115 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);
118 if (rc != 0) {117 if (rc != 0) {
119 zig_panic("posix_spawn failed: %s", strerror(rc));118 zig_panic("posix_spawn failed: %s", strerror(rc));
120 }119 }
...@@ -126,16 +125,14 @@ static void os_spawn_process_posix(const char *exe, ZigList<const char *> &args,...@@ -126,16 +125,14 @@ static void os_spawn_process_posix(const char *exe, ZigList<const char *> &args,
126#endif125#endif
127126
128#if defined(ZIG_OS_WINDOWS)127#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 = "\"";
136 for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {132 for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {
137 buf_append_str(command_line, " \"");
138 const char *arg = args.at(arg_i);133 const char *arg = args.at(arg_i);
134 buf_append_str(command_line, prefix);
135 prefix = " \"";
139 size_t arg_len = strlen(arg);136 size_t arg_len = strlen(arg);
140 for (size_t c_i = 0; c_i < arg_len; c_i += 1) {137 for (size_t c_i = 0; c_i < arg_len; c_i += 1) {
141 if (arg[c_i] == '\"') {138 if (arg[c_i] == '\"') {
...@@ -147,14 +144,15 @@ static void os_windows_create_command_line(Buf *command_line, const char *exe, Z...@@ -147,14 +144,15 @@ static void os_windows_create_command_line(Buf *command_line, const char *exe, Z
147 }144 }
148}145}
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) {
151 Buf command_line = BUF_INIT;148 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
154 PROCESS_INFORMATION piProcInfo = {0};151 PROCESS_INFORMATION piProcInfo = {0};
155 STARTUPINFO siStartInfo = {0};152 STARTUPINFO siStartInfo = {0};
156 siStartInfo.cb = sizeof(STARTUPINFO);153 siStartInfo.cb = sizeof(STARTUPINFO);
157154
155 const char *exe = args.at(0);
158 BOOL success = CreateProcessA(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,156 BOOL success = CreateProcessA(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,
159 &siStartInfo, &piProcInfo);157 &siStartInfo, &piProcInfo);
160158
...@@ -173,11 +171,11 @@ static void os_spawn_process_windows(const char *exe, ZigList<const char *> &arg...@@ -173,11 +171,11 @@ static void os_spawn_process_windows(const char *exe, ZigList<const char *> &arg
173}171}
174#endif172#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) {
177#if defined(ZIG_OS_WINDOWS)175#if defined(ZIG_OS_WINDOWS)
178 os_spawn_process_windows(exe, args, term);176 os_spawn_process_windows(args, term);
179#elif defined(ZIG_OS_POSIX)177#elif defined(ZIG_OS_POSIX)
180 os_spawn_process_posix(exe, args, term);178 os_spawn_process_posix(args, term);
181#else179#else
182#error "missing os_spawn_process implementation"180#error "missing os_spawn_process implementation"
183#endif181#endif
...@@ -785,7 +783,7 @@ Error os_file_exists(Buf *full_path, bool *result) {...@@ -785,7 +783,7 @@ Error os_file_exists(Buf *full_path, bool *result) {
785}783}
786784
787#if defined(ZIG_OS_POSIX)785#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,
789 Termination *term, Buf *out_stderr, Buf *out_stdout)787 Termination *term, Buf *out_stderr, Buf *out_stdout)
790{788{
791 int stdin_pipe[2];789 int stdin_pipe[2];
...@@ -817,13 +815,12 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args,...@@ -817,13 +815,12 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args,
817 if (dup2(stderr_pipe[1], STDERR_FILENO) == -1)815 if (dup2(stderr_pipe[1], STDERR_FILENO) == -1)
818 zig_panic("dup2 failed");816 zig_panic("dup2 failed");
819817
820 const char **argv = allocate<const char *>(args.length + 2);818 const char **argv = allocate<const char *>(args.length + 1);
821 argv[0] = exe;819 argv[args.length] = nullptr;
822 argv[args.length + 1] = nullptr;
823 for (size_t i = 0; i < args.length; i += 1) {820 for (size_t i = 0; i < args.length; i += 1) {
824 argv[i + 1] = args.at(i);821 argv[i] = args.at(i);
825 }822 }
826 execvp(exe, const_cast<char * const *>(argv));823 execvp(argv[0], const_cast<char * const *>(argv));
827 Error report_err = ErrorUnexpected;824 Error report_err = ErrorUnexpected;
828 if (errno == ENOENT) {825 if (errno == ENOENT) {
829 report_err = ErrorFileNotFound;826 report_err = ErrorFileNotFound;
...@@ -874,11 +871,11 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args,...@@ -874,11 +871,11 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args,
874// LocalFree(messageBuffer);871// LocalFree(messageBuffer);
875//}872//}
876873
877static Error os_exec_process_windows(const char *exe, ZigList<const char *> &args,874static Error os_exec_process_windows(ZigList<const char *> &args,
878 Termination *term, Buf *out_stderr, Buf *out_stdout)875 Termination *term, Buf *out_stderr, Buf *out_stdout)
879{876{
880 Buf command_line = BUF_INIT;877 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
883 HANDLE g_hChildStd_IN_Rd = NULL;880 HANDLE g_hChildStd_IN_Rd = NULL;
884 HANDLE g_hChildStd_IN_Wr = NULL;881 HANDLE g_hChildStd_IN_Wr = NULL;
...@@ -925,6 +922,7 @@ static Error os_exec_process_windows(const char *exe, ZigList<const char *> &arg...@@ -925,6 +922,7 @@ static Error os_exec_process_windows(const char *exe, ZigList<const char *> &arg
925 siStartInfo.hStdInput = g_hChildStd_IN_Rd;922 siStartInfo.hStdInput = g_hChildStd_IN_Rd;
926 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;923 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
927924
925 const char *exe = args.at(0);
928 BOOL success = CreateProcess(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,926 BOOL success = CreateProcess(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,
929 &siStartInfo, &piProcInfo);927 &siStartInfo, &piProcInfo);
930928
...@@ -1005,13 +1003,13 @@ Error os_execv(const char *exe, const char **argv) {...@@ -1005,13 +1003,13 @@ Error os_execv(const char *exe, const char **argv) {
1005#endif1003#endif
1006}1004}
10071005
1008Error os_exec_process(const char *exe, ZigList<const char *> &args,1006Error os_exec_process(ZigList<const char *> &args,
1009 Termination *term, Buf *out_stderr, Buf *out_stdout)1007 Termination *term, Buf *out_stderr, Buf *out_stdout)
1010{1008{
1011#if defined(ZIG_OS_WINDOWS)1009#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);
1013#elif defined(ZIG_OS_POSIX)1011#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);
1015#else1013#else
1016#error "missing os_exec_process implementation"1014#error "missing os_exec_process implementation"
1017#endif1015#endif
src/os.hpp+2-2
...@@ -100,8 +100,8 @@ struct OsFileAttr {...@@ -100,8 +100,8 @@ struct OsFileAttr {
100100
101int os_init(void);101int os_init(void);
102102
103void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term);103void os_spawn_process(ZigList<const char *> &args, Termination *term);
104Error os_exec_process(const char *exe, ZigList<const char *> &args,104Error os_exec_process(ZigList<const char *> &args,
105 Termination *term, Buf *out_stderr, Buf *out_stdout);105 Termination *term, Buf *out_stderr, Buf *out_stdout);
106Error os_execv(const char *exe, const char **argv);106Error 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 {...@@ -100,7 +100,7 @@ pub fn Queue(comptime T: type) type {
100 pub fn isEmpty(self: *Self) bool {100 pub fn isEmpty(self: *Self) bool {
101 const held = self.mutex.acquire();101 const held = self.mutex.acquire();
102 defer held.release();102 defer held.release();
103 return self.head != null;103 return self.head == null;
104 }104 }
105105
106 pub fn dump(self: *Self) void {106 pub fn dump(self: *Self) void {
...@@ -172,12 +172,14 @@ test "std.atomic.Queue" {...@@ -172,12 +172,14 @@ test "std.atomic.Queue" {
172 };172 };
173173
174 if (builtin.single_threaded) {174 if (builtin.single_threaded) {
175 expect(context.queue.isEmpty());
175 {176 {
176 var i: usize = 0;177 var i: usize = 0;
177 while (i < put_thread_count) : (i += 1) {178 while (i < put_thread_count) : (i += 1) {
178 expect(startPuts(&context) == 0);179 expect(startPuts(&context) == 0);
179 }180 }
180 }181 }
182 expect(!context.queue.isEmpty());
181 context.puts_done = 1;183 context.puts_done = 1;
182 {184 {
183 var i: usize = 0;185 var i: usize = 0;
...@@ -185,7 +187,10 @@ test "std.atomic.Queue" {...@@ -185,7 +187,10 @@ test "std.atomic.Queue" {
185 expect(startGets(&context) == 0);187 expect(startGets(&context) == 0);
186 }188 }
187 }189 }
190 expect(context.queue.isEmpty());
188 } else {191 } else {
192 expect(context.queue.isEmpty());
193
189 var putters: [put_thread_count]*std.Thread = undefined;194 var putters: [put_thread_count]*std.Thread = undefined;
190 for (putters) |*t| {195 for (putters) |*t| {
191 t.* = try std.Thread.spawn(&context, startPuts);196 t.* = try std.Thread.spawn(&context, startPuts);
...@@ -200,6 +205,8 @@ test "std.atomic.Queue" {...@@ -200,6 +205,8 @@ test "std.atomic.Queue" {
200 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);205 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
201 for (getters) |t|206 for (getters) |t|
202 t.wait();207 t.wait();
208
209 expect(context.queue.isEmpty());
203 }210 }
204211
205 if (context.put_sum != context.get_sum) {212 if (context.put_sum != context.get_sum) {
...@@ -250,6 +257,7 @@ fn startGets(ctx: *Context) u8 {...@@ -250,6 +257,7 @@ fn startGets(ctx: *Context) u8 {
250257
251test "std.atomic.Queue single-threaded" {258test "std.atomic.Queue single-threaded" {
252 var queue = Queue(i32).init();259 var queue = Queue(i32).init();
260 expect(queue.isEmpty());
253261
254 var node_0 = Queue(i32).Node{262 var node_0 = Queue(i32).Node{
255 .data = 0,263 .data = 0,
...@@ -257,6 +265,7 @@ test "std.atomic.Queue single-threaded" {...@@ -257,6 +265,7 @@ test "std.atomic.Queue single-threaded" {
257 .prev = undefined,265 .prev = undefined,
258 };266 };
259 queue.put(&node_0);267 queue.put(&node_0);
268 expect(!queue.isEmpty());
260269
261 var node_1 = Queue(i32).Node{270 var node_1 = Queue(i32).Node{
262 .data = 1,271 .data = 1,
...@@ -264,8 +273,10 @@ test "std.atomic.Queue single-threaded" {...@@ -264,8 +273,10 @@ test "std.atomic.Queue single-threaded" {
264 .prev = undefined,273 .prev = undefined,
265 };274 };
266 queue.put(&node_1);275 queue.put(&node_1);
276 expect(!queue.isEmpty());
267277
268 expect(queue.get().?.data == 0);278 expect(queue.get().?.data == 0);
279 expect(!queue.isEmpty());
269280
270 var node_2 = Queue(i32).Node{281 var node_2 = Queue(i32).Node{
271 .data = 2,282 .data = 2,
...@@ -273,6 +284,7 @@ test "std.atomic.Queue single-threaded" {...@@ -273,6 +284,7 @@ test "std.atomic.Queue single-threaded" {
273 .prev = undefined,284 .prev = undefined,
274 };285 };
275 queue.put(&node_2);286 queue.put(&node_2);
287 expect(!queue.isEmpty());
276288
277 var node_3 = Queue(i32).Node{289 var node_3 = Queue(i32).Node{
278 .data = 3,290 .data = 3,
...@@ -280,10 +292,13 @@ test "std.atomic.Queue single-threaded" {...@@ -280,10 +292,13 @@ test "std.atomic.Queue single-threaded" {
280 .prev = undefined,292 .prev = undefined,
281 };293 };
282 queue.put(&node_3);294 queue.put(&node_3);
295 expect(!queue.isEmpty());
283296
284 expect(queue.get().?.data == 1);297 expect(queue.get().?.data == 1);
298 expect(!queue.isEmpty());
285299
286 expect(queue.get().?.data == 2);300 expect(queue.get().?.data == 2);
301 expect(!queue.isEmpty());
287302
288 var node_4 = Queue(i32).Node{303 var node_4 = Queue(i32).Node{
289 .data = 4,304 .data = 4,
...@@ -291,13 +306,17 @@ test "std.atomic.Queue single-threaded" {...@@ -291,13 +306,17 @@ test "std.atomic.Queue single-threaded" {
291 .prev = undefined,306 .prev = undefined,
292 };307 };
293 queue.put(&node_4);308 queue.put(&node_4);
309 expect(!queue.isEmpty());
294310
295 expect(queue.get().?.data == 3);311 expect(queue.get().?.data == 3);
296 node_3.next = null;312 node_3.next = null;
313 expect(!queue.isEmpty());
297314
298 expect(queue.get().?.data == 4);315 expect(queue.get().?.data == 4);
316 expect(queue.isEmpty());
299317
300 expect(queue.get() == null);318 expect(queue.get() == null);
319 expect(queue.isEmpty());
301}320}
302321
303test "std.atomic.Queue dump" {322test "std.atomic.Queue dump" {
std/child_process.zig+22-15
...@@ -543,25 +543,32 @@ pub const ChildProcess = struct {...@@ -543,25 +543,32 @@ pub const ChildProcess = struct {
543543
544 const PATH = try process.getEnvVarOwned(self.allocator, "PATH");544 const PATH = try process.getEnvVarOwned(self.allocator, "PATH");
545 defer self.allocator.free(PATH);545 defer self.allocator.free(PATH);
546 const PATHEXT = try process.getEnvVarOwned(self.allocator, "PATHEXT");
547 defer self.allocator.free(PATHEXT);
546548
547 var it = mem.tokenize(PATH, ";");549 var it = mem.tokenize(PATH, ";");
548 while (it.next()) |search_path| {550 retry: while (it.next()) |search_path| {
549 const joined_path = try fs.path.join(self.allocator, [_][]const u8{ search_path, app_name });551 var ext_it = mem.tokenize(PATHEXT, ";");
550 defer self.allocator.free(joined_path);552 while (ext_it.next()) |app_ext| {
551553 const app_basename = try mem.concat(self.allocator, u8, [_][]const u8{app_name[0..app_name.len - 1], app_ext});
552 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);554 defer self.allocator.free(app_basename);
553 defer self.allocator.free(joined_path_w);555
554556 const joined_path = try fs.path.join(self.allocator, [_][]const u8{ search_path, app_basename });
555 if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {557 defer self.allocator.free(joined_path);
556 break;558
557 } else |err| if (err == error.FileNotFound) {559 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);
558 continue;560 defer self.allocator.free(joined_path_w);
559 } else {561
560 return err;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 }
561 }569 }
562 } else {570 } else {
563 // Every other error would have been returned earlier.571 return no_path_err; // return the original error
564 return error.FileNotFound;
565 }572 }
566 };573 };
567574
std/crypto.zig+3
...@@ -13,6 +13,8 @@ pub const Sha3_256 = sha3.Sha3_256;...@@ -13,6 +13,8 @@ pub const Sha3_256 = sha3.Sha3_256;
13pub const Sha3_384 = sha3.Sha3_384;13pub const Sha3_384 = sha3.Sha3_384;
14pub const Sha3_512 = sha3.Sha3_512;14pub const Sha3_512 = sha3.Sha3_512;
1515
16pub const gimli = @import("crypto/gimli.zig");
17
16const blake2 = @import("crypto/blake2.zig");18const blake2 = @import("crypto/blake2.zig");
17pub const Blake2s224 = blake2.Blake2s224;19pub const Blake2s224 = blake2.Blake2s224;
18pub const Blake2s256 = blake2.Blake2s256;20pub const Blake2s256 = blake2.Blake2s256;
...@@ -38,6 +40,7 @@ pub const randomBytes = std.os.getrandom;...@@ -38,6 +40,7 @@ pub const randomBytes = std.os.getrandom;
38test "crypto" {40test "crypto" {
39 _ = @import("crypto/blake2.zig");41 _ = @import("crypto/blake2.zig");
40 _ = @import("crypto/chacha20.zig");42 _ = @import("crypto/chacha20.zig");
43 _ = @import("crypto/gimli.zig");
41 _ = @import("crypto/hmac.zig");44 _ = @import("crypto/hmac.zig");
42 _ = @import("crypto/md5.zig");45 _ = @import("crypto/md5.zig");
43 _ = @import("crypto/poly1305.zig");46 _ = @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;...@@ -13,7 +13,13 @@ pub const default_max_depth = 3;
13/// Renders fmt string with args, calling output with slices of bytes.13/// Renders fmt string with args, calling output with slices of bytes.
14/// If `output` returns an error, the error is returned from `format` and14/// If `output` returns an error, the error is returned from `format` and
15/// `output` is not called again.15/// `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 {
17 const State = enum {23 const State = enum {
18 Start,24 Start,
19 OpenBrace,25 OpenBrace,
...@@ -28,7 +34,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),...@@ -28,7 +34,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
2834
29 inline for (fmt) |c, i| {35 inline for (fmt) |c, i| {
30 switch (state) {36 switch (state) {
31 State.Start => switch (c) {37 .Start => switch (c) {
32 '{' => {38 '{' => {
33 if (start_index < i) {39 if (start_index < i) {
34 try output(context, fmt[start_index..i]);40 try output(context, fmt[start_index..i]);
...@@ -45,7 +51,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),...@@ -45,7 +51,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
45 },51 },
46 else => {},52 else => {},
47 },53 },
48 State.OpenBrace => switch (c) {54 .OpenBrace => switch (c) {
49 '{' => {55 '{' => {
50 state = State.Start;56 state = State.Start;
51 start_index = i;57 start_index = i;
...@@ -61,14 +67,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),...@@ -61,14 +67,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
61 state = State.FormatString;67 state = State.FormatString;
62 },68 },
63 },69 },
64 State.CloseBrace => switch (c) {70 .CloseBrace => switch (c) {
65 '}' => {71 '}' => {
66 state = State.Start;72 state = State.Start;
67 start_index = i;73 start_index = i;
68 },74 },
69 else => @compileError("Single '}' encountered in format string"),75 else => @compileError("Single '}' encountered in format string"),
70 },76 },
71 State.FormatString => switch (c) {77 .FormatString => switch (c) {
72 '}' => {78 '}' => {
73 const s = start_index + 1;79 const s = start_index + 1;
74 try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth);80 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),...@@ -78,7 +84,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context),
78 },84 },
79 else => {},85 else => {},
80 },86 },
81 State.Pointer => switch (c) {87 .Pointer => switch (c) {
82 '}' => {88 '}' => {
83 try output(context, @typeName(@typeOf(args[next_arg]).Child));89 try output(context, @typeName(@typeOf(args[next_arg]).Child));
84 try output(context, "@");90 try output(context, "@");
...@@ -114,88 +120,93 @@ pub fn formatType(...@@ -114,88 +120,93 @@ pub fn formatType(
114) Errors!void {120) Errors!void {
115 const T = @typeOf(value);121 const T = @typeOf(value);
116 switch (@typeInfo(T)) {122 switch (@typeInfo(T)) {
117 builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {123 .ComptimeInt, .Int, .Float => {
118 return formatValue(value, fmt, context, Errors, output);124 return formatValue(value, fmt, context, Errors, output);
119 },125 },
120 builtin.TypeId.Void => {126 .Void => {
121 return output(context, "void");127 return output(context, "void");
122 },128 },
123 builtin.TypeId.Bool => {129 .Bool => {
124 return output(context, if (value) "true" else "false");130 return output(context, if (value) "true" else "false");
125 },131 },
126 builtin.TypeId.Optional => {132 .Optional => {
127 if (value) |payload| {133 if (value) |payload| {
128 return formatType(payload, fmt, context, Errors, output, max_depth);134 return formatType(payload, fmt, context, Errors, output, max_depth);
129 } else {135 } else {
130 return output(context, "null");136 return output(context, "null");
131 }137 }
132 },138 },
133 builtin.TypeId.ErrorUnion => {139 .ErrorUnion => {
134 if (value) |payload| {140 if (value) |payload| {
135 return formatType(payload, fmt, context, Errors, output, max_depth);141 return formatType(payload, fmt, context, Errors, output, max_depth);
136 } else |err| {142 } else |err| {
137 return formatType(err, fmt, context, Errors, output, max_depth);143 return formatType(err, fmt, context, Errors, output, max_depth);
138 }144 }
139 },145 },
140 builtin.TypeId.ErrorSet => {146 .ErrorSet => {
141 try output(context, "error.");147 try output(context, "error.");
142 return output(context, @errorName(value));148 return output(context, @errorName(value));
143 },149 },
144 builtin.TypeId.Promise => {150 .Promise => {
145 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));151 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
146 },152 },
147 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {153 .Enum => {
148 if (comptime std.meta.trait.hasFn("format")(T)) return value.format(fmt, context, Errors, output);154 if (comptime std.meta.trait.hasFn("format")(T)) {
155 return value.format(fmt, context, Errors, output);
156 }
149157
150 try output(context, @typeName(T));158 try output(context, @typeName(T));
151 switch (comptime @typeId(T)) {159 try output(context, ".");
152 builtin.TypeId.Enum => {160 return formatType(@tagName(value), "", context, Errors, output, max_depth);
153 try output(context, ".");161 },
154 try formatType(@tagName(value), "", context, Errors, output, max_depth);162 .Union => {
155 return;163 if (comptime std.meta.trait.hasFn("format")(T)) {
156 },164 return value.format(fmt, context, Errors, output);
157 builtin.TypeId.Struct => {165 }
158 if (max_depth == 0) {166
159 return output(context, "{ ... }");167 try output(context, @typeName(T));
160 }168 if (max_depth == 0) {
161 comptime var field_i = 0;169 return output(context, "{ ... }");
162 inline while (field_i < @memberCount(T)) : (field_i += 1) {170 }
163 if (field_i == 0) {171 const info = @typeInfo(T).Union;
164 try output(context, "{ .");172 if (info.tag_type) |UnionTagType| {
165 } else {173 try output(context, "{ .");
166 try output(context, ", .");174 try output(context, @tagName(UnionTagType(value)));
167 }175 try output(context, " = ");
168 try output(context, @memberName(T, field_i));176 inline for (info.fields) |u_field| {
169 try output(context, " = ");177 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
170 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);178 try formatType(@field(value, u_field.name), "", 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));
191 }179 }
192 },180 }
193 else => unreachable,181 try output(context, " }");
182 } else {
183 try format(context, Errors, output, "@{x}", @ptrToInt(&value));
194 }184 }
195 return;
196 },185 },
197 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {186 .Struct => {
198 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {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)) {
199 builtin.TypeId.Array => |info| {210 builtin.TypeId.Array => |info| {
200 if (info.child == u8) {211 if (info.child == u8) {
201 return formatText(value, fmt, context, Errors, output);212 return formatText(value, fmt, context, Errors, output);
...@@ -207,7 +218,7 @@ pub fn formatType(...@@ -207,7 +218,7 @@ pub fn formatType(
207 },218 },
208 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),219 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
209 },220 },
210 builtin.TypeInfo.Pointer.Size.Many => {221 .Many => {
211 if (ptr_info.child == u8) {222 if (ptr_info.child == u8) {
212 if (fmt.len > 0 and fmt[0] == 's') {223 if (fmt.len > 0 and fmt[0] == 's') {
213 const len = mem.len(u8, value);224 const len = mem.len(u8, value);
...@@ -216,7 +227,7 @@ pub fn formatType(...@@ -216,7 +227,7 @@ pub fn formatType(
216 }227 }
217 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));228 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
218 },229 },
219 builtin.TypeInfo.Pointer.Size.Slice => {230 .Slice => {
220 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {231 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
221 return formatText(value, fmt, context, Errors, output);232 return formatText(value, fmt, context, Errors, output);
222 }233 }
...@@ -225,17 +236,17 @@ pub fn formatType(...@@ -225,17 +236,17 @@ pub fn formatType(
225 }236 }
226 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));237 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));
227 },238 },
228 builtin.TypeInfo.Pointer.Size.C => {239 .C => {
229 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));240 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
230 },241 },
231 },242 },
232 builtin.TypeId.Array => |info| {243 .Array => |info| {
233 if (info.child == u8) {244 if (info.child == u8) {
234 return formatText(value, fmt, context, Errors, output);245 return formatText(value, fmt, context, Errors, output);
235 }246 }
236 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
237 },248 },
238 builtin.TypeId.Fn => {249 .Fn => {
239 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));250 return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
240 },251 },
241 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),252 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
...@@ -249,24 +260,24 @@ fn formatValue(...@@ -249,24 +260,24 @@ fn formatValue(
249 comptime Errors: type,260 comptime Errors: type,
250 output: fn (@typeOf(context), []const u8) Errors!void,261 output: fn (@typeOf(context), []const u8) Errors!void,
251) Errors!void {262) Errors!void {
252 if (fmt.len > 0) {263 if (fmt.len > 0 and fmt[0] == 'B') {
253 if (fmt[0] == 'B') {264 comptime var width: ?usize = null;
254 comptime var width: ?usize = null;265 if (fmt.len > 1) {
255 if (fmt.len > 1) {266 if (fmt[1] == 'i') {
256 if (fmt[1] == 'i') {267 if (fmt.len > 2) {
257 if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);268 width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
258 return formatBytes(value, width, 1024, context, Errors, output);
259 }269 }
260 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);270 return formatBytes(value, width, 1024, context, Errors, output);
261 }271 }
262 return formatBytes(value, width, 1000, context, Errors, output);272 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
263 }273 }
274 return formatBytes(value, width, 1000, context, Errors, output);
264 }275 }
265276
266 const T = @typeOf(value);277 const T = @typeOf(value);
267 switch (@typeId(T)) {278 switch (@typeId(T)) {
268 builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),279 .Float => return formatFloatValue(value, fmt, context, Errors, output),
269 builtin.TypeId.Int, builtin.TypeId.ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),280 .Int, .ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),
270 else => comptime unreachable,281 else => comptime unreachable,
271 }282 }
272}283}
...@@ -797,7 +808,7 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {...@@ -797,7 +808,7 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
797 }808 }
798}809}
799810
800test "fmt.parseInt" {811test "parseInt" {
801 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);812 testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
802 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);813 testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
803 testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);814 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...@@ -828,7 +839,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
828 return x;839 return x;
829}840}
830841
831test "fmt.parseUnsigned" {842test "parseUnsigned" {
832 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);843 testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
833 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);844 testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
834 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));845 testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
...@@ -913,7 +924,7 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {...@@ -913,7 +924,7 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
913 size.* += bytes.len;924 size.* += bytes.len;
914}925}
915926
916test "buf print int" {927test "bufPrintInt" {
917 var buffer: [100]u8 = undefined;928 var buffer: [100]u8 = undefined;
918 const buf = buffer[0..];929 const buf = buffer[0..];
919 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));930 testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
...@@ -949,7 +960,7 @@ test "parse unsigned comptime" {...@@ -949,7 +960,7 @@ test "parse unsigned comptime" {
949 }960 }
950}961}
951962
952test "fmt.format" {963test "fmt.optional" {
953 {964 {
954 const value: ?i32 = 1234;965 const value: ?i32 = 1234;
955 try testFmt("optional: 1234\n", "optional: {}\n", value);966 try testFmt("optional: 1234\n", "optional: {}\n", value);
...@@ -958,6 +969,9 @@ test "fmt.format" {...@@ -958,6 +969,9 @@ test "fmt.format" {
958 const value: ?i32 = null;969 const value: ?i32 = null;
959 try testFmt("optional: null\n", "optional: {}\n", value);970 try testFmt("optional: null\n", "optional: {}\n", value);
960 }971 }
972}
973
974test "fmt.error" {
961 {975 {
962 const value: anyerror!i32 = 1234;976 const value: anyerror!i32 = 1234;
963 try testFmt("error union: 1234\n", "error union: {}\n", value);977 try testFmt("error union: 1234\n", "error union: {}\n", value);
...@@ -966,10 +980,16 @@ test "fmt.format" {...@@ -966,10 +980,16 @@ test "fmt.format" {
966 const value: anyerror!i32 = error.InvalidChar;980 const value: anyerror!i32 = error.InvalidChar;
967 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);981 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
968 }982 }
983}
984
985test "fmt.int.small" {
969 {986 {
970 const value: u3 = 0b101;987 const value: u3 = 0b101;
971 try testFmt("u3: 5\n", "u3: {}\n", value);988 try testFmt("u3: 5\n", "u3: {}\n", value);
972 }989 }
990}
991
992test "fmt.int.specifier" {
973 {993 {
974 const value: u8 = 'a';994 const value: u8 = 'a';
975 try testFmt("u8: a\n", "u8: {c}\n", value);995 try testFmt("u8: a\n", "u8: {c}\n", value);
...@@ -978,6 +998,9 @@ test "fmt.format" {...@@ -978,6 +998,9 @@ test "fmt.format" {
978 const value: u8 = 0b1100;998 const value: u8 = 0b1100;
979 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);999 try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
980 }1000 }
1001}
1002
1003test "fmt.buffer" {
981 {1004 {
982 var buf1: [32]u8 = undefined;1005 var buf1: [32]u8 = undefined;
983 var context = BufPrintContext{ .remaining = buf1[0..] };1006 var context = BufPrintContext{ .remaining = buf1[0..] };
...@@ -995,6 +1018,9 @@ test "fmt.format" {...@@ -995,6 +1018,9 @@ test "fmt.format" {
995 res = buf1[0 .. buf1.len - context.remaining.len];1018 res = buf1[0 .. buf1.len - context.remaining.len];
996 testing.expect(mem.eql(u8, res, "1100"));1019 testing.expect(mem.eql(u8, res, "1100"));
997 }1020 }
1021}
1022
1023test "fmt.array" {
998 {1024 {
999 const value: [3]u8 = "abc";1025 const value: [3]u8 = "abc";
1000 try testFmt("array: abc\n", "array: {}\n", value);1026 try testFmt("array: abc\n", "array: {}\n", value);
...@@ -1007,6 +1033,9 @@ test "fmt.format" {...@@ -1007,6 +1033,9 @@ test "fmt.format" {
1007 &value,1033 &value,
1008 );1034 );
1009 }1035 }
1036}
1037
1038test "fmt.slice" {
1010 {1039 {
1011 const value: []const u8 = "abc";1040 const value: []const u8 = "abc";
1012 try testFmt("slice: abc\n", "slice: {}\n", value);1041 try testFmt("slice: abc\n", "slice: {}\n", value);
...@@ -1015,6 +1044,12 @@ test "fmt.format" {...@@ -1015,6 +1044,12 @@ test "fmt.format" {
1015 const value = @intToPtr([*]const []const u8, 0xdeadbeef)[0..0];1044 const value = @intToPtr([*]const []const u8, 0xdeadbeef)[0..0];
1016 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);1045 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);
1017 }1046 }
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" {
1018 {1053 {
1019 const value = @intToPtr(*i32, 0xdeadbeef);1054 const value = @intToPtr(*i32, 0xdeadbeef);
1020 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);1055 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
...@@ -1028,12 +1063,19 @@ test "fmt.format" {...@@ -1028,12 +1063,19 @@ test "fmt.format" {
1028 const value = @intToPtr(fn () void, 0xdeadbeef);1063 const value = @intToPtr(fn () void, 0xdeadbeef);
1029 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);1064 try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
1030 }1065 }
1031 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");1066}
1032 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");1067
1068test "fmt.cstr" {
1033 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");1069 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
1034 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");1070 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
1071}
1072
1073test "fmt.filesize" {
1035 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));1074 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
1036 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));1075 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
1076}
1077
1078test "fmt.struct" {
1037 {1079 {
1038 const Struct = struct {1080 const Struct = struct {
1039 field: u8,1081 field: u8,
...@@ -1050,15 +1092,19 @@ test "fmt.format" {...@@ -1050,15 +1092,19 @@ test "fmt.format" {
1050 const value = Struct{ .a = 0, .b = 1 };1092 const value = Struct{ .a = 0, .b = 1 };
1051 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);1093 try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
1052 }1094 }
1053 {1095}
1054 const Enum = enum {1096
1055 One,1097test "fmt.enum" {
1056 Two,1098 const Enum = enum {
1057 };1099 One,
1058 const value = Enum.Two;1100 Two,
1059 try testFmt("enum: Enum.Two\n", "enum: {}\n", value);1101 };
1060 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);1102 const value = Enum.Two;
1061 }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" {
1062 {1108 {
1063 var buf1: [32]u8 = undefined;1109 var buf1: [32]u8 = undefined;
1064 const value: f32 = 1.34;1110 const value: f32 = 1.34;
...@@ -1088,6 +1134,9 @@ test "fmt.format" {...@@ -1088,6 +1134,9 @@ test "fmt.format" {
1088 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));1134 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
1089 }1135 }
1090 }1136 }
1137}
1138
1139test "fmt.float.scientific.precision" {
1091 {1140 {
1092 var buf1: [32]u8 = undefined;1141 var buf1: [32]u8 = undefined;
1093 const value: f64 = 1.409706e-42;1142 const value: f64 = 1.409706e-42;
...@@ -1114,6 +1163,9 @@ test "fmt.format" {...@@ -1114,6 +1163,9 @@ test "fmt.format" {
1114 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);1163 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1115 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));1164 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
1116 }1165 }
1166}
1167
1168test "fmt.float.special" {
1117 {1169 {
1118 var buf1: [32]u8 = undefined;1170 var buf1: [32]u8 = undefined;
1119 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);1171 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
...@@ -1136,6 +1188,9 @@ test "fmt.format" {...@@ -1136,6 +1188,9 @@ test "fmt.format" {
1136 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);1188 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
1137 testing.expect(mem.eql(u8, result, "f64: -inf\n"));1189 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
1138 }1190 }
1191}
1192
1193test "fmt.float.decimal" {
1139 {1194 {
1140 var buf1: [64]u8 = undefined;1195 var buf1: [64]u8 = undefined;
1141 const value: f64 = 1.52314e+29;1196 const value: f64 = 1.52314e+29;
...@@ -1216,7 +1271,9 @@ test "fmt.format" {...@@ -1216,7 +1271,9 @@ test "fmt.format" {
1216 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1271 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1217 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));1272 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1218 }1273 }
1219 // libc checks1274}
1275
1276test "fmt.float.libc.sanity" {
1220 {1277 {
1221 var buf1: [32]u8 = undefined;1278 var buf1: [32]u8 = undefined;
1222 const value: f64 = f64(@bitCast(f32, u32(916964781)));1279 const value: f64 = f64(@bitCast(f32, u32(916964781)));
...@@ -1267,127 +1324,127 @@ test "fmt.format" {...@@ -1267,127 +1324,127 @@ test "fmt.format" {
1267 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1324 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1268 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));1325 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
1269 }1326 }
1270 //custom type format1327}
1271 {1328
1272 const Vec2 = struct {1329test "fmt.custom" {
1273 const SelfType = @This();1330 const Vec2 = struct {
1274 x: f32,1331 const SelfType = @This();
1275 y: f32,1332 x: f32,
12761333 y: f32,
1277 pub fn format(1334
1278 self: SelfType,1335 pub fn format(
1279 comptime fmt: []const u8,1336 self: SelfType,
1280 context: var,1337 comptime fmt: []const u8,
1281 comptime Errors: type,1338 context: var,
1282 output: fn (@typeOf(context), []const u8) Errors!void,1339 comptime Errors: type,
1283 ) Errors!void {1340 output: fn (@typeOf(context), []const u8) Errors!void,
1284 switch (fmt.len) {1341 ) Errors!void {
1285 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1342 switch (fmt.len) {
1286 1 => switch (fmt[0]) {1343 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1287 //point format1344 1 => switch (fmt[0]) {
1288 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1345 //point format
1289 //dimension format1346 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1290 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),1347 //dimension format
1291 else => unreachable,1348 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1292 },
1293 else => unreachable,1349 else => unreachable,
1294 }1350 },
1351 else => unreachable,
1295 }1352 }
1296 };1353 }
1354 };
12971355
1298 var buf1: [32]u8 = undefined;1356 var buf1: [32]u8 = undefined;
1299 var value = Vec2{1357 var value = Vec2{
1300 .x = 10.2,1358 .x = 10.2,
1301 .y = 2.22,1359 .y = 2.22,
1302 };1360 };
1303 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);1361 try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
1304 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);1362 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
13051363
1306 // same thing but not passing a pointer1364 // same thing but not passing a pointer
1307 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);1365 try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
1308 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);1366 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1309 }1367}
1310 //struct format
1311 {
1312 const S = struct {
1313 a: u32,
1314 b: anyerror,
1315 };
13161368
1317 const inst = S{1369test "fmt.struct" {
1318 .a = 456,1370 const S = struct {
1319 .b = error.Unused,1371 a: u32,
1320 };1372 b: anyerror,
1373 };
13211374
1322 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);1375 const inst = S{
1323 }1376 .a = 456,
1324 //union format1377 .b = error.Unused,
1325 {1378 };
1326 const TU = union(enum) {
1327 float: f32,
1328 int: u32,
1329 };
13301379
1331 const UU = union {1380 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1332 float: f32,1381}
1333 int: u32,
1334 };
13351382
1336 const EU = extern union {1383test "fmt.union" {
1337 float: f32,1384 const TU = union(enum) {
1338 int: u32,1385 float: f32,
1339 };1386 int: u32,
1387 };
13401388
1341 const tu_inst = TU{ .int = 123 };1389 const UU = union {
1342 const uu_inst = UU{ .int = 456 };1390 float: f32,
1343 const eu_inst = EU{ .float = 321.123 };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;1399 const tu_inst = TU{ .int = 123 };
1348 const uu_result = try bufPrint(buf[0..], "{}", uu_inst);1400 const uu_inst = UU{ .int = 456 };
1349 testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));1401 const eu_inst = EU{ .float = 321.123 };
13501402
1351 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);1403 try testFmt("TU{ .int = 123 }", "{}", tu_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 };
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);1409 const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
1365 }1410 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1366 //self-referential struct format1411}
1367 {
1368 const S = struct {
1369 const SelfType = @This();
1370 a: ?*SelfType,
1371 };
13721412
1373 var inst = S{1413test "fmt.enum" {
1374 .a = null,1414 const E = enum {
1375 };1415 One,
1376 inst.a = &inst;1416 Two,
1417 Three,
1418 };
13771419
1378 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);1420 const inst = E.Two;
1379 }1421
1380 //print bytes as hex1422 try testFmt("E.Two", "{}", inst);
1381 {1423}
1382 const some_bytes = "\xCA\xFE\xBA\xBE";1424
1383 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);1425test "fmt.struct.self-referential" {
1384 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);1426 const S = struct {
1385 //Test Slices1427 const SelfType = @This();
1386 try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);1428 a: ?*SelfType,
1387 try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);1429 };
1388 const bytes_with_zeros = "\x00\x0E\xBA\xBE";1430
1389 try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);1431 var inst = S{
1390 }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);
1391}1448}
13921449
1393fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {1450fn 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...@@ -564,12 +564,12 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
564 },564 },
565565
566 builtin.TypeId.Float => |info| {566 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);
568 },568 },
569 builtin.TypeId.Bool => return autoHash(@boolToInt(key), rng),569 builtin.TypeId.Bool => return autoHash(@boolToInt(key), rng, HashInt),
570 builtin.TypeId.Enum => return autoHash(@enumToInt(key), rng),570 builtin.TypeId.Enum => return autoHash(@enumToInt(key), rng, HashInt),
571 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng),571 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng, HashInt),
572 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng),572 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng, HashInt),
573573
574 builtin.TypeId.BoundFn,574 builtin.TypeId.BoundFn,
575 builtin.TypeId.ComptimeFloat,575 builtin.TypeId.ComptimeFloat,
std/mem.zig+37
...@@ -996,6 +996,43 @@ test "mem.join" {...@@ -996,6 +996,43 @@ test "mem.join" {
996 testing.expect(eql(u8, try join(a, ",", [_][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c"));996 testing.expect(eql(u8, try join(a, ",", [_][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c"));
997}997}
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
999test "testStringEquality" {1036test "testStringEquality" {
1000 testing.expect(eql(u8, "abcd", "abcd"));1037 testing.expect(eql(u8, "abcd", "abcd"));
1001 testing.expect(!eql(u8, "abcdef", "abZdef"));1038 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...@@ -632,6 +632,7 @@ pub fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) G
632632
633pub const CreateProcessError = error{633pub const CreateProcessError = error{
634 FileNotFound,634 FileNotFound,
635 AccessDenied,
635 InvalidName,636 InvalidName,
636 Unexpected,637 Unexpected,
637};638};
...@@ -663,6 +664,7 @@ pub fn CreateProcessW(...@@ -663,6 +664,7 @@ pub fn CreateProcessW(
663 switch (kernel32.GetLastError()) {664 switch (kernel32.GetLastError()) {
664 ERROR.FILE_NOT_FOUND => return error.FileNotFound,665 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
665 ERROR.PATH_NOT_FOUND => return error.FileNotFound,666 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
667 ERROR.ACCESS_DENIED => return error.AccessDenied,
666 ERROR.INVALID_PARAMETER => unreachable,668 ERROR.INVALID_PARAMETER => unreachable,
667 ERROR.INVALID_NAME => return error.InvalidName,669 ERROR.INVALID_NAME => return error.InvalidName,
668 else => |err| return unexpectedError(err),670 else => |err| return unexpectedError(err),
test/stage1/behavior/slice.zig+11
...@@ -54,3 +54,14 @@ test "comptime slices are disambiguated" {...@@ -54,3 +54,14 @@ test "comptime slices are disambiguated" {
54 expect(sliceSum([_]u8{ 1, 2 }) == 3);54 expect(sliceSum([_]u8{ 1, 2 }) == 3);
55 expect(sliceSum([_]u8{ 3, 4 }) == 7);55 expect(sliceSum([_]u8{ 3, 4 }) == 7);
56}56}
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 @@...@@ -1,7 +1,9 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const mem = @import("std").mem;2const expect = std.testing.expect;
3const TypeInfo = @import("builtin").TypeInfo;3const mem = std.mem;
4const TypeId = @import("builtin").TypeId;4const builtin = @import("builtin");
5const TypeInfo = builtin.TypeInfo;
6const TypeId = builtin.TypeId;
57
6test "type info: tag type, void info" {8test "type info: tag type, void info" {
7 testBasic();9 testBasic();
...@@ -317,3 +319,20 @@ test "type info: TypeId -> TypeInfo impl cast" {...@@ -317,3 +319,20 @@ test "type info: TypeId -> TypeInfo impl cast" {
317 _ = passTypeInfo(TypeId.Void);319 _ = passTypeInfo(TypeId.Void);
318 _ = comptime passTypeInfo(TypeId.Void);320 _ = comptime passTypeInfo(TypeId.Void);
319}321}
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}