| author | |
| committer | |
| log | 04c25efe112e374facaf1bc8b58bbdb6999a39e3 |
| tree | 66a70b185ad8e44a69c8be27dd7dbc23425b040c |
| parent | 4ffab5b85f03f63a7e724698482f8497cacc7212 |
| parent | 381c6a38b145665a22440f7aa816f0ddd9b70ee5 |
| signature |
20 files changed, 604 insertions(+), 277 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -479,6 +479,7 @@ set(ZIG_STD_FILES |
| 479 | 479 | "crypto.zig" |
| 480 | 480 | "crypto/blake2.zig" |
| 481 | 481 | "crypto/chacha20.zig" |
| 482 | "crypto/gimli.zig" | |
| 482 | 483 | "crypto/hmac.zig" |
| 483 | 484 | "crypto/md5.zig" |
| 484 | 485 | "crypto/poly1305.zig" |
doc/langref.html.in+1-1| ... | ... | @@ -4927,7 +4927,7 @@ test "peer type resolution: *const T and ?*T" { |
| 4927 | 4927 | <li>The {#link|Integers#} {#syntax#}u0{#endsyntax#} and {#syntax#}i0{#endsyntax#}.</li> |
| 4928 | 4928 | <li>{#link|Arrays#} and {#link|Vectors#} with len 0, or with an element type that is a zero bit type.</li> |
| 4929 | 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 | 4931 | <li>A {#link|union#} with only 1 field which is a zero bit type.</li> |
| 4932 | 4932 | <li>{#link|Pointers to Zero Bit Types#} are themselves zero bit types.</li> |
| 4933 | 4933 | </ul> |
src/buffer.hpp+2| ... | ... | @@ -27,11 +27,13 @@ Buf *buf_sprintf(const char *format, ...) |
| 27 | 27 | Buf *buf_vprintf(const char *format, va_list ap); |
| 28 | 28 | |
| 29 | 29 | static inline size_t buf_len(Buf *buf) { |
| 30 | assert(buf); | |
| 30 | 31 | assert(buf->list.length); |
| 31 | 32 | return buf->list.length - 1; |
| 32 | 33 | } |
| 33 | 34 | |
| 34 | 35 | static inline char *buf_ptr(Buf *buf) { |
| 36 | assert(buf); | |
| 35 | 37 | assert(buf->list.length); |
| 36 | 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 | 8732 | |
| 8733 | 8733 | Termination term; |
| 8734 | 8734 | ZigList<const char *> args = {}; |
| 8735 | args.append(buf_ptr(self_exe_path)); | |
| 8735 | 8736 | args.append("cc"); |
| 8736 | 8737 | |
| 8737 | 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 | 8751 | if (g->verbose_cc) { |
| 8751 | 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 | 8755 | if (term.how != TerminationIdClean || term.code != 0) { |
| 8755 | 8756 | fprintf(stderr, "\nThe following command failed:\n"); |
| 8756 | 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 | 18046 | case ZigTypeIdPromise: |
| 18047 | 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 | 18052 | return ira->codegen->invalid_instruction; |
| 18051 | 18053 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 18052 | 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 | 19903 | true, false, PtrLenUnknown, |
| 19902 | 19904 | 0, 0, 0, false); |
| 19903 | 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 | 19907 | fn_decl_fields[6].data.x_optional = create_const_vals(1); |
| 19906 | 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 | 19911 | } else { |
| 19909 | 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 | 153 | const char *cc_exe = getenv("CC"); |
| 154 | 154 | cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe; |
| 155 | 155 | ZigList<const char *> args = {}; |
| 156 | args.append(cc_exe); | |
| 156 | 157 | args.append("-E"); |
| 157 | 158 | args.append("-Wp,-v"); |
| 158 | 159 | args.append("-xc"); |
| ... | ... | @@ -166,7 +167,7 @@ static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, b |
| 166 | 167 | Buf *out_stderr = buf_alloc(); |
| 167 | 168 | Buf *out_stdout = buf_alloc(); |
| 168 | 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 | 171 | if (verbose) { |
| 171 | 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 | 278 | const char *cc_exe = getenv("CC"); |
| 278 | 279 | cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe; |
| 279 | 280 | ZigList<const char *> args = {}; |
| 281 | args.append(cc_exe); | |
| 280 | 282 | args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file))); |
| 281 | 283 | Termination term; |
| 282 | 284 | Buf *out_stderr = buf_alloc(); |
| 283 | 285 | Buf *out_stdout = buf_alloc(); |
| 284 | 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 | 288 | if (err == ErrorFileNotFound) |
| 287 | 289 | return ErrorNoCCompilerInstalled; |
| 288 | 290 | if (verbose) { |
src/link.cpp+2-1| ... | ... | @@ -1721,10 +1721,11 @@ void codegen_link(CodeGen *g) { |
| 1721 | 1721 | if (g->system_linker_hack && g->zig_target->os == OsMacOSX) { |
| 1722 | 1722 | Termination term; |
| 1723 | 1723 | ZigList<const char *> args = {}; |
| 1724 | args.append("ld"); | |
| 1724 | 1725 | for (size_t i = 1; i < lj.args.length; i += 1) { |
| 1725 | 1726 | args.append(lj.args.at(i)); |
| 1726 | 1727 | } |
| 1727 | os_spawn_process("ld", args, &term); | |
| 1728 | os_spawn_process(args, &term); | |
| 1728 | 1729 | if (term.how != TerminationIdClean || term.code != 0) { |
| 1729 | 1730 | exit(1); |
| 1730 | 1731 | } |
src/main.cpp+12-16| ... | ... | @@ -467,6 +467,7 @@ int main(int argc, char **argv) { |
| 467 | 467 | init_all_targets(); |
| 468 | 468 | |
| 469 | 469 | ZigList<const char *> args = {0}; |
| 470 | args.append(NULL); // placeholder | |
| 470 | 471 | args.append(zig_exe_path); |
| 471 | 472 | args.append(NULL); // placeholder |
| 472 | 473 | args.append(NULL); // placeholder |
| ... | ... | @@ -525,8 +526,8 @@ int main(int argc, char **argv) { |
| 525 | 526 | g->enable_time_report = timing_info; |
| 526 | 527 | codegen_set_out_name(g, buf_create_from_str("build")); |
| 527 | 528 | |
| 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); | |
| 530 | 531 | |
| 531 | 532 | bool build_file_exists; |
| 532 | 533 | if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { |
| ... | ... | @@ -580,12 +581,14 @@ int main(int argc, char **argv) { |
| 580 | 581 | codegen_build_and_link(g); |
| 581 | 582 | |
| 582 | 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 | 586 | if (term.how != TerminationIdClean || term.code != 0) { |
| 585 | 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 | 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 | 593 | fprintf(stderr, "\n"); |
| 591 | 594 | } |
| ... | ... | @@ -1161,7 +1164,7 @@ int main(int argc, char **argv) { |
| 1161 | 1164 | |
| 1162 | 1165 | args.pop(); |
| 1163 | 1166 | Termination term; |
| 1164 | os_spawn_process(exec_path, args, &term); | |
| 1167 | os_spawn_process(args, &term); | |
| 1165 | 1168 | return term.code; |
| 1166 | 1169 | } else if (cmd == CmdBuild) { |
| 1167 | 1170 | if (g->enable_cache) { |
| ... | ... | @@ -1213,17 +1216,10 @@ int main(int argc, char **argv) { |
| 1213 | 1216 | } |
| 1214 | 1217 | |
| 1215 | 1218 | 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)); | |
| 1225 | 1221 | } |
| 1226 | ||
| 1222 | os_spawn_process(test_exec_args, &term); | |
| 1227 | 1223 | if (term.how != TerminationIdClean || term.code != 0) { |
| 1228 | 1224 | fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); |
| 1229 | 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 | 105 | } |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | static 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; | |
| 108 | static void os_spawn_process_posix(ZigList<const char *> &args, Termination *term) { | |
| 109 | const char **argv = allocate<const char *>(args.length + 1); | |
| 112 | 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; | |
| 115 | 114 | |
| 116 | 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 | 117 | if (rc != 0) { |
| 119 | 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 | 125 | #endif |
| 127 | 126 | |
| 128 | 127 | #if defined(ZIG_OS_WINDOWS) |
| 129 | static 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, '\"'); | |
| 135 | 128 | |
| 129 | static void os_windows_create_command_line(Buf *command_line, ZigList<const char *> &args) { | |
| 130 | buf_resize(command_line, 0); | |
| 131 | char *prefix = "\""; | |
| 136 | 132 | for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) { |
| 137 | buf_append_str(command_line, " \""); | |
| 138 | 133 | const char *arg = args.at(arg_i); |
| 134 | buf_append_str(command_line, prefix); | |
| 135 | prefix = " \""; | |
| 139 | 136 | size_t arg_len = strlen(arg); |
| 140 | 137 | for (size_t c_i = 0; c_i < arg_len; c_i += 1) { |
| 141 | 138 | if (arg[c_i] == '\"') { |
| ... | ... | @@ -147,14 +144,15 @@ static void os_windows_create_command_line(Buf *command_line, const char *exe, Z |
| 147 | 144 | } |
| 148 | 145 | } |
| 149 | 146 | |
| 150 | static void os_spawn_process_windows(const char *exe, ZigList<const char *> &args, Termination *term) { | |
| 147 | static void os_spawn_process_windows(ZigList<const char *> &args, Termination *term) { | |
| 151 | 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); | |
| 153 | 150 | |
| 154 | 151 | PROCESS_INFORMATION piProcInfo = {0}; |
| 155 | 152 | STARTUPINFO siStartInfo = {0}; |
| 156 | 153 | siStartInfo.cb = sizeof(STARTUPINFO); |
| 157 | 154 | |
| 155 | const char *exe = args.at(0); | |
| 158 | 156 | BOOL success = CreateProcessA(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr, |
| 159 | 157 | &siStartInfo, &piProcInfo); |
| 160 | 158 | |
| ... | ... | @@ -173,11 +171,11 @@ static void os_spawn_process_windows(const char *exe, ZigList<const char *> &arg |
| 173 | 171 | } |
| 174 | 172 | #endif |
| 175 | 173 | |
| 176 | void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term) { | |
| 174 | void os_spawn_process(ZigList<const char *> &args, Termination *term) { | |
| 177 | 175 | #if defined(ZIG_OS_WINDOWS) |
| 178 | os_spawn_process_windows(exe, args, term); | |
| 176 | os_spawn_process_windows(args, term); | |
| 179 | 177 | #elif defined(ZIG_OS_POSIX) |
| 180 | os_spawn_process_posix(exe, args, term); | |
| 178 | os_spawn_process_posix(args, term); | |
| 181 | 179 | #else |
| 182 | 180 | #error "missing os_spawn_process implementation" |
| 183 | 181 | #endif |
| ... | ... | @@ -785,7 +783,7 @@ Error os_file_exists(Buf *full_path, bool *result) { |
| 785 | 783 | } |
| 786 | 784 | |
| 787 | 785 | #if defined(ZIG_OS_POSIX) |
| 788 | static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args, | |
| 786 | static Error os_exec_process_posix(ZigList<const char *> &args, | |
| 789 | 787 | Termination *term, Buf *out_stderr, Buf *out_stdout) |
| 790 | 788 | { |
| 791 | 789 | int stdin_pipe[2]; |
| ... | ... | @@ -817,13 +815,12 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args, |
| 817 | 815 | if (dup2(stderr_pipe[1], STDERR_FILENO) == -1) |
| 818 | 816 | zig_panic("dup2 failed"); |
| 819 | 817 | |
| 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; | |
| 823 | 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 | 824 | Error report_err = ErrorUnexpected; |
| 828 | 825 | if (errno == ENOENT) { |
| 829 | 826 | report_err = ErrorFileNotFound; |
| ... | ... | @@ -874,11 +871,11 @@ static Error os_exec_process_posix(const char *exe, ZigList<const char *> &args, |
| 874 | 871 | // LocalFree(messageBuffer); |
| 875 | 872 | //} |
| 876 | 873 | |
| 877 | static Error os_exec_process_windows(const char *exe, ZigList<const char *> &args, | |
| 874 | static Error os_exec_process_windows(ZigList<const char *> &args, | |
| 878 | 875 | Termination *term, Buf *out_stderr, Buf *out_stdout) |
| 879 | 876 | { |
| 880 | 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); | |
| 882 | 879 | |
| 883 | 880 | HANDLE g_hChildStd_IN_Rd = NULL; |
| 884 | 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 | 922 | siStartInfo.hStdInput = g_hChildStd_IN_Rd; |
| 926 | 923 | siStartInfo.dwFlags |= STARTF_USESTDHANDLES; |
| 927 | 924 | |
| 925 | const char *exe = args.at(0); | |
| 928 | 926 | BOOL success = CreateProcess(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr, |
| 929 | 927 | &siStartInfo, &piProcInfo); |
| 930 | 928 | |
| ... | ... | @@ -1005,13 +1003,13 @@ Error os_execv(const char *exe, const char **argv) { |
| 1005 | 1003 | #endif |
| 1006 | 1004 | } |
| 1007 | 1005 | |
| 1008 | Error os_exec_process(const char *exe, ZigList<const char *> &args, | |
| 1006 | Error os_exec_process(ZigList<const char *> &args, | |
| 1009 | 1007 | Termination *term, Buf *out_stderr, Buf *out_stdout) |
| 1010 | 1008 | { |
| 1011 | 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 | 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 | 1013 | #else |
| 1016 | 1014 | #error "missing os_exec_process implementation" |
| 1017 | 1015 | #endif |
src/os.hpp+2-2| ... | ... | @@ -100,8 +100,8 @@ struct OsFileAttr { |
| 100 | 100 | |
| 101 | 101 | int os_init(void); |
| 102 | 102 | |
| 103 | void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term); | |
| 104 | Error os_exec_process(const char *exe, ZigList<const char *> &args, | |
| 103 | void os_spawn_process(ZigList<const char *> &args, Termination *term); | |
| 104 | Error os_exec_process(ZigList<const char *> &args, | |
| 105 | 105 | Termination *term, Buf *out_stderr, Buf *out_stdout); |
| 106 | 106 | Error os_execv(const char *exe, const char **argv); |
| 107 | 107 |
std/atomic/queue.zig+20-1| ... | ... | @@ -100,7 +100,7 @@ pub fn Queue(comptime T: type) type { |
| 100 | 100 | pub fn isEmpty(self: *Self) bool { |
| 101 | 101 | const held = self.mutex.acquire(); |
| 102 | 102 | defer held.release(); |
| 103 | return self.head != null; | |
| 103 | return self.head == null; | |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | pub fn dump(self: *Self) void { |
| ... | ... | @@ -172,12 +172,14 @@ test "std.atomic.Queue" { |
| 172 | 172 | }; |
| 173 | 173 | |
| 174 | 174 | if (builtin.single_threaded) { |
| 175 | expect(context.queue.isEmpty()); | |
| 175 | 176 | { |
| 176 | 177 | var i: usize = 0; |
| 177 | 178 | while (i < put_thread_count) : (i += 1) { |
| 178 | 179 | expect(startPuts(&context) == 0); |
| 179 | 180 | } |
| 180 | 181 | } |
| 182 | expect(!context.queue.isEmpty()); | |
| 181 | 183 | context.puts_done = 1; |
| 182 | 184 | { |
| 183 | 185 | var i: usize = 0; |
| ... | ... | @@ -185,7 +187,10 @@ test "std.atomic.Queue" { |
| 185 | 187 | expect(startGets(&context) == 0); |
| 186 | 188 | } |
| 187 | 189 | } |
| 190 | expect(context.queue.isEmpty()); | |
| 188 | 191 | } else { |
| 192 | expect(context.queue.isEmpty()); | |
| 193 | ||
| 189 | 194 | var putters: [put_thread_count]*std.Thread = undefined; |
| 190 | 195 | for (putters) |*t| { |
| 191 | 196 | t.* = try std.Thread.spawn(&context, startPuts); |
| ... | ... | @@ -200,6 +205,8 @@ test "std.atomic.Queue" { |
| 200 | 205 | _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); |
| 201 | 206 | for (getters) |t| |
| 202 | 207 | t.wait(); |
| 208 | ||
| 209 | expect(context.queue.isEmpty()); | |
| 203 | 210 | } |
| 204 | 211 | |
| 205 | 212 | if (context.put_sum != context.get_sum) { |
| ... | ... | @@ -250,6 +257,7 @@ fn startGets(ctx: *Context) u8 { |
| 250 | 257 | |
| 251 | 258 | test "std.atomic.Queue single-threaded" { |
| 252 | 259 | var queue = Queue(i32).init(); |
| 260 | expect(queue.isEmpty()); | |
| 253 | 261 | |
| 254 | 262 | var node_0 = Queue(i32).Node{ |
| 255 | 263 | .data = 0, |
| ... | ... | @@ -257,6 +265,7 @@ test "std.atomic.Queue single-threaded" { |
| 257 | 265 | .prev = undefined, |
| 258 | 266 | }; |
| 259 | 267 | queue.put(&node_0); |
| 268 | expect(!queue.isEmpty()); | |
| 260 | 269 | |
| 261 | 270 | var node_1 = Queue(i32).Node{ |
| 262 | 271 | .data = 1, |
| ... | ... | @@ -264,8 +273,10 @@ test "std.atomic.Queue single-threaded" { |
| 264 | 273 | .prev = undefined, |
| 265 | 274 | }; |
| 266 | 275 | queue.put(&node_1); |
| 276 | expect(!queue.isEmpty()); | |
| 267 | 277 | |
| 268 | 278 | expect(queue.get().?.data == 0); |
| 279 | expect(!queue.isEmpty()); | |
| 269 | 280 | |
| 270 | 281 | var node_2 = Queue(i32).Node{ |
| 271 | 282 | .data = 2, |
| ... | ... | @@ -273,6 +284,7 @@ test "std.atomic.Queue single-threaded" { |
| 273 | 284 | .prev = undefined, |
| 274 | 285 | }; |
| 275 | 286 | queue.put(&node_2); |
| 287 | expect(!queue.isEmpty()); | |
| 276 | 288 | |
| 277 | 289 | var node_3 = Queue(i32).Node{ |
| 278 | 290 | .data = 3, |
| ... | ... | @@ -280,10 +292,13 @@ test "std.atomic.Queue single-threaded" { |
| 280 | 292 | .prev = undefined, |
| 281 | 293 | }; |
| 282 | 294 | queue.put(&node_3); |
| 295 | expect(!queue.isEmpty()); | |
| 283 | 296 | |
| 284 | 297 | expect(queue.get().?.data == 1); |
| 298 | expect(!queue.isEmpty()); | |
| 285 | 299 | |
| 286 | 300 | expect(queue.get().?.data == 2); |
| 301 | expect(!queue.isEmpty()); | |
| 287 | 302 | |
| 288 | 303 | var node_4 = Queue(i32).Node{ |
| 289 | 304 | .data = 4, |
| ... | ... | @@ -291,13 +306,17 @@ test "std.atomic.Queue single-threaded" { |
| 291 | 306 | .prev = undefined, |
| 292 | 307 | }; |
| 293 | 308 | queue.put(&node_4); |
| 309 | expect(!queue.isEmpty()); | |
| 294 | 310 | |
| 295 | 311 | expect(queue.get().?.data == 3); |
| 296 | 312 | node_3.next = null; |
| 313 | expect(!queue.isEmpty()); | |
| 297 | 314 | |
| 298 | 315 | expect(queue.get().?.data == 4); |
| 316 | expect(queue.isEmpty()); | |
| 299 | 317 | |
| 300 | 318 | expect(queue.get() == null); |
| 319 | expect(queue.isEmpty()); | |
| 301 | 320 | } |
| 302 | 321 | |
| 303 | 322 | test "std.atomic.Queue dump" { |
std/child_process.zig+22-15| ... | ... | @@ -543,25 +543,32 @@ pub const ChildProcess = struct { |
| 543 | 543 | |
| 544 | 544 | const PATH = try process.getEnvVarOwned(self.allocator, "PATH"); |
| 545 | 545 | defer self.allocator.free(PATH); |
| 546 | const PATHEXT = try process.getEnvVarOwned(self.allocator, "PATHEXT"); | |
| 547 | defer self.allocator.free(PATHEXT); | |
| 546 | 548 | |
| 547 | 549 | 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 | } | |
| 561 | 569 | } |
| 562 | 570 | } else { |
| 563 | // Every other error would have been returned earlier. | |
| 564 | return error.FileNotFound; | |
| 571 | return no_path_err; // return the original error | |
| 565 | 572 | } |
| 566 | 573 | }; |
| 567 | 574 |
std/crypto.zig+3| ... | ... | @@ -13,6 +13,8 @@ pub const Sha3_256 = sha3.Sha3_256; |
| 13 | 13 | pub const Sha3_384 = sha3.Sha3_384; |
| 14 | 14 | pub const Sha3_512 = sha3.Sha3_512; |
| 15 | 15 | |
| 16 | pub const gimli = @import("crypto/gimli.zig"); | |
| 17 | ||
| 16 | 18 | const blake2 = @import("crypto/blake2.zig"); |
| 17 | 19 | pub const Blake2s224 = blake2.Blake2s224; |
| 18 | 20 | pub const Blake2s256 = blake2.Blake2s256; |
| ... | ... | @@ -38,6 +40,7 @@ pub const randomBytes = std.os.getrandom; |
| 38 | 40 | test "crypto" { |
| 39 | 41 | _ = @import("crypto/blake2.zig"); |
| 40 | 42 | _ = @import("crypto/chacha20.zig"); |
| 43 | _ = @import("crypto/gimli.zig"); | |
| 41 | 44 | _ = @import("crypto/hmac.zig"); |
| 42 | 45 | _ = @import("crypto/md5.zig"); |
| 43 | 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 | ||
| 10 | const std = @import("../std.zig"); | |
| 11 | const mem = std.mem; | |
| 12 | const math = std.math; | |
| 13 | const debug = std.debug; | |
| 14 | const assert = std.debug.assert; | |
| 15 | const testing = std.testing; | |
| 16 | const htest = @import("test.zig"); | |
| 17 | ||
| 18 | pub 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 | ||
| 77 | test "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 | ||
| 102 | pub 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 | ||
| 155 | pub fn hash(out: []u8, in: []const u8) void { | |
| 156 | var st = Hash.init(); | |
| 157 | st.update(in); | |
| 158 | st.final(out); | |
| 159 | } | |
| 160 | ||
| 161 | test "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 | 13 | /// Renders fmt string with args, calling output with slices of bytes. |
| 14 | 14 | /// If `output` returns an error, the error is returned from `format` and |
| 15 | 15 | /// `output` is not called again. |
| 16 | pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void { | |
| 16 | pub 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 | 23 | const State = enum { |
| 18 | 24 | Start, |
| 19 | 25 | OpenBrace, |
| ... | ... | @@ -28,7 +34,7 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), |
| 28 | 34 | |
| 29 | 35 | inline for (fmt) |c, i| { |
| 30 | 36 | switch (state) { |
| 31 | State.Start => switch (c) { | |
| 37 | .Start => switch (c) { | |
| 32 | 38 | '{' => { |
| 33 | 39 | if (start_index < i) { |
| 34 | 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 | 51 | }, |
| 46 | 52 | else => {}, |
| 47 | 53 | }, |
| 48 | State.OpenBrace => switch (c) { | |
| 54 | .OpenBrace => switch (c) { | |
| 49 | 55 | '{' => { |
| 50 | 56 | state = State.Start; |
| 51 | 57 | start_index = i; |
| ... | ... | @@ -61,14 +67,14 @@ pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), |
| 61 | 67 | state = State.FormatString; |
| 62 | 68 | }, |
| 63 | 69 | }, |
| 64 | State.CloseBrace => switch (c) { | |
| 70 | .CloseBrace => switch (c) { | |
| 65 | 71 | '}' => { |
| 66 | 72 | state = State.Start; |
| 67 | 73 | start_index = i; |
| 68 | 74 | }, |
| 69 | 75 | else => @compileError("Single '}' encountered in format string"), |
| 70 | 76 | }, |
| 71 | State.FormatString => switch (c) { | |
| 77 | .FormatString => switch (c) { | |
| 72 | 78 | '}' => { |
| 73 | 79 | const s = start_index + 1; |
| 74 | 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 | 84 | }, |
| 79 | 85 | else => {}, |
| 80 | 86 | }, |
| 81 | State.Pointer => switch (c) { | |
| 87 | .Pointer => switch (c) { | |
| 82 | 88 | '}' => { |
| 83 | 89 | try output(context, @typeName(@typeOf(args[next_arg]).Child)); |
| 84 | 90 | try output(context, "@"); |
| ... | ... | @@ -114,88 +120,93 @@ pub fn formatType( |
| 114 | 120 | ) Errors!void { |
| 115 | 121 | const T = @typeOf(value); |
| 116 | 122 | switch (@typeInfo(T)) { |
| 117 | builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => { | |
| 123 | .ComptimeInt, .Int, .Float => { | |
| 118 | 124 | return formatValue(value, fmt, context, Errors, output); |
| 119 | 125 | }, |
| 120 | builtin.TypeId.Void => { | |
| 126 | .Void => { | |
| 121 | 127 | return output(context, "void"); |
| 122 | 128 | }, |
| 123 | builtin.TypeId.Bool => { | |
| 129 | .Bool => { | |
| 124 | 130 | return output(context, if (value) "true" else "false"); |
| 125 | 131 | }, |
| 126 | builtin.TypeId.Optional => { | |
| 132 | .Optional => { | |
| 127 | 133 | if (value) |payload| { |
| 128 | 134 | return formatType(payload, fmt, context, Errors, output, max_depth); |
| 129 | 135 | } else { |
| 130 | 136 | return output(context, "null"); |
| 131 | 137 | } |
| 132 | 138 | }, |
| 133 | builtin.TypeId.ErrorUnion => { | |
| 139 | .ErrorUnion => { | |
| 134 | 140 | if (value) |payload| { |
| 135 | 141 | return formatType(payload, fmt, context, Errors, output, max_depth); |
| 136 | 142 | } else |err| { |
| 137 | 143 | return formatType(err, fmt, context, Errors, output, max_depth); |
| 138 | 144 | } |
| 139 | 145 | }, |
| 140 | builtin.TypeId.ErrorSet => { | |
| 146 | .ErrorSet => { | |
| 141 | 147 | try output(context, "error."); |
| 142 | 148 | return output(context, @errorName(value)); |
| 143 | 149 | }, |
| 144 | builtin.TypeId.Promise => { | |
| 150 | .Promise => { | |
| 145 | 151 | return format(context, Errors, output, "promise@{x}", @ptrToInt(value)); |
| 146 | 152 | }, |
| 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 | } | |
| 149 | 157 | |
| 150 | 158 | 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); | |
| 191 | 179 | } |
| 192 | }, | |
| 193 | else => unreachable, | |
| 180 | } | |
| 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) { | |
| 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)) { | |
| 199 | 210 | builtin.TypeId.Array => |info| { |
| 200 | 211 | if (info.child == u8) { |
| 201 | 212 | return formatText(value, fmt, context, Errors, output); |
| ... | ... | @@ -207,7 +218,7 @@ pub fn formatType( |
| 207 | 218 | }, |
| 208 | 219 | else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)), |
| 209 | 220 | }, |
| 210 | builtin.TypeInfo.Pointer.Size.Many => { | |
| 221 | .Many => { | |
| 211 | 222 | if (ptr_info.child == u8) { |
| 212 | 223 | if (fmt.len > 0 and fmt[0] == 's') { |
| 213 | 224 | const len = mem.len(u8, value); |
| ... | ... | @@ -216,7 +227,7 @@ pub fn formatType( |
| 216 | 227 | } |
| 217 | 228 | return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)); |
| 218 | 229 | }, |
| 219 | builtin.TypeInfo.Pointer.Size.Slice => { | |
| 230 | .Slice => { | |
| 220 | 231 | if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) { |
| 221 | 232 | return formatText(value, fmt, context, Errors, output); |
| 222 | 233 | } |
| ... | ... | @@ -225,17 +236,17 @@ pub fn formatType( |
| 225 | 236 | } |
| 226 | 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 | 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 | 244 | if (info.child == u8) { |
| 234 | 245 | return formatText(value, fmt, context, Errors, output); |
| 235 | 246 | } |
| 236 | 247 | return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value)); |
| 237 | 248 | }, |
| 238 | builtin.TypeId.Fn => { | |
| 249 | .Fn => { | |
| 239 | 250 | return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value)); |
| 240 | 251 | }, |
| 241 | 252 | else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"), |
| ... | ... | @@ -249,24 +260,24 @@ fn formatValue( |
| 249 | 260 | comptime Errors: type, |
| 250 | 261 | output: fn (@typeOf(context), []const u8) Errors!void, |
| 251 | 262 | ) 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); | |
| 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 | } |
| 265 | 276 | |
| 266 | 277 | const T = @typeOf(value); |
| 267 | 278 | 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), | |
| 270 | 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 | 808 | } |
| 798 | 809 | } |
| 799 | 810 | |
| 800 | test "fmt.parseInt" { | |
| 811 | test "parseInt" { | |
| 801 | 812 | testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10); |
| 802 | 813 | testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10); |
| 803 | 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 | 839 | return x; |
| 829 | 840 | } |
| 830 | 841 | |
| 831 | test "fmt.parseUnsigned" { | |
| 842 | test "parseUnsigned" { | |
| 832 | 843 | testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); |
| 833 | 844 | testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); |
| 834 | 845 | testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); |
| ... | ... | @@ -913,7 +924,7 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) { |
| 913 | 924 | size.* += bytes.len; |
| 914 | 925 | } |
| 915 | 926 | |
| 916 | test "buf print int" { | |
| 927 | test "bufPrintInt" { | |
| 917 | 928 | var buffer: [100]u8 = undefined; |
| 918 | 929 | const buf = buffer[0..]; |
| 919 | 930 | testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110")); |
| ... | ... | @@ -949,7 +960,7 @@ test "parse unsigned comptime" { |
| 949 | 960 | } |
| 950 | 961 | } |
| 951 | 962 | |
| 952 | test "fmt.format" { | |
| 963 | test "fmt.optional" { | |
| 953 | 964 | { |
| 954 | 965 | const value: ?i32 = 1234; |
| 955 | 966 | try testFmt("optional: 1234\n", "optional: {}\n", value); |
| ... | ... | @@ -958,6 +969,9 @@ test "fmt.format" { |
| 958 | 969 | const value: ?i32 = null; |
| 959 | 970 | try testFmt("optional: null\n", "optional: {}\n", value); |
| 960 | 971 | } |
| 972 | } | |
| 973 | ||
| 974 | test "fmt.error" { | |
| 961 | 975 | { |
| 962 | 976 | const value: anyerror!i32 = 1234; |
| 963 | 977 | try testFmt("error union: 1234\n", "error union: {}\n", value); |
| ... | ... | @@ -966,10 +980,16 @@ test "fmt.format" { |
| 966 | 980 | const value: anyerror!i32 = error.InvalidChar; |
| 967 | 981 | try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value); |
| 968 | 982 | } |
| 983 | } | |
| 984 | ||
| 985 | test "fmt.int.small" { | |
| 969 | 986 | { |
| 970 | 987 | const value: u3 = 0b101; |
| 971 | 988 | try testFmt("u3: 5\n", "u3: {}\n", value); |
| 972 | 989 | } |
| 990 | } | |
| 991 | ||
| 992 | test "fmt.int.specifier" { | |
| 973 | 993 | { |
| 974 | 994 | const value: u8 = 'a'; |
| 975 | 995 | try testFmt("u8: a\n", "u8: {c}\n", value); |
| ... | ... | @@ -978,6 +998,9 @@ test "fmt.format" { |
| 978 | 998 | const value: u8 = 0b1100; |
| 979 | 999 | try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value); |
| 980 | 1000 | } |
| 1001 | } | |
| 1002 | ||
| 1003 | test "fmt.buffer" { | |
| 981 | 1004 | { |
| 982 | 1005 | var buf1: [32]u8 = undefined; |
| 983 | 1006 | var context = BufPrintContext{ .remaining = buf1[0..] }; |
| ... | ... | @@ -995,6 +1018,9 @@ test "fmt.format" { |
| 995 | 1018 | res = buf1[0 .. buf1.len - context.remaining.len]; |
| 996 | 1019 | testing.expect(mem.eql(u8, res, "1100")); |
| 997 | 1020 | } |
| 1021 | } | |
| 1022 | ||
| 1023 | test "fmt.array" { | |
| 998 | 1024 | { |
| 999 | 1025 | const value: [3]u8 = "abc"; |
| 1000 | 1026 | try testFmt("array: abc\n", "array: {}\n", value); |
| ... | ... | @@ -1007,6 +1033,9 @@ test "fmt.format" { |
| 1007 | 1033 | &value, |
| 1008 | 1034 | ); |
| 1009 | 1035 | } |
| 1036 | } | |
| 1037 | ||
| 1038 | test "fmt.slice" { | |
| 1010 | 1039 | { |
| 1011 | 1040 | const value: []const u8 = "abc"; |
| 1012 | 1041 | try testFmt("slice: abc\n", "slice: {}\n", value); |
| ... | ... | @@ -1015,6 +1044,12 @@ test "fmt.format" { |
| 1015 | 1044 | const value = @intToPtr([*]const []const u8, 0xdeadbeef)[0..0]; |
| 1016 | 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 | ||
| 1052 | test "fmt.pointer" { | |
| 1018 | 1053 | { |
| 1019 | 1054 | const value = @intToPtr(*i32, 0xdeadbeef); |
| 1020 | 1055 | try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value); |
| ... | ... | @@ -1028,12 +1063,19 @@ test "fmt.format" { |
| 1028 | 1063 | const value = @intToPtr(fn () void, 0xdeadbeef); |
| 1029 | 1064 | try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value); |
| 1030 | 1065 | } |
| 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 | ||
| 1068 | test "fmt.cstr" { | |
| 1033 | 1069 | try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C"); |
| 1034 | 1070 | try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C"); |
| 1071 | } | |
| 1072 | ||
| 1073 | test "fmt.filesize" { | |
| 1035 | 1074 | try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024)); |
| 1036 | 1075 | try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024)); |
| 1076 | } | |
| 1077 | ||
| 1078 | test "fmt.struct" { | |
| 1037 | 1079 | { |
| 1038 | 1080 | const Struct = struct { |
| 1039 | 1081 | field: u8, |
| ... | ... | @@ -1050,15 +1092,19 @@ test "fmt.format" { |
| 1050 | 1092 | const value = Struct{ .a = 0, .b = 1 }; |
| 1051 | 1093 | try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value); |
| 1052 | 1094 | } |
| 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 | ||
| 1097 | test "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 | ||
| 1107 | test "fmt.float.scientific" { | |
| 1062 | 1108 | { |
| 1063 | 1109 | var buf1: [32]u8 = undefined; |
| 1064 | 1110 | const value: f32 = 1.34; |
| ... | ... | @@ -1088,6 +1134,9 @@ test "fmt.format" { |
| 1088 | 1134 | testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n")); |
| 1089 | 1135 | } |
| 1090 | 1136 | } |
| 1137 | } | |
| 1138 | ||
| 1139 | test "fmt.float.scientific.precision" { | |
| 1091 | 1140 | { |
| 1092 | 1141 | var buf1: [32]u8 = undefined; |
| 1093 | 1142 | const value: f64 = 1.409706e-42; |
| ... | ... | @@ -1114,6 +1163,9 @@ test "fmt.format" { |
| 1114 | 1163 | const result = try bufPrint(buf1[0..], "f64: {e5}\n", value); |
| 1115 | 1164 | testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n")); |
| 1116 | 1165 | } |
| 1166 | } | |
| 1167 | ||
| 1168 | test "fmt.float.special" { | |
| 1117 | 1169 | { |
| 1118 | 1170 | var buf1: [32]u8 = undefined; |
| 1119 | 1171 | const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); |
| ... | ... | @@ -1136,6 +1188,9 @@ test "fmt.format" { |
| 1136 | 1188 | const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); |
| 1137 | 1189 | testing.expect(mem.eql(u8, result, "f64: -inf\n")); |
| 1138 | 1190 | } |
| 1191 | } | |
| 1192 | ||
| 1193 | test "fmt.float.decimal" { | |
| 1139 | 1194 | { |
| 1140 | 1195 | var buf1: [64]u8 = undefined; |
| 1141 | 1196 | const value: f64 = 1.52314e+29; |
| ... | ... | @@ -1216,7 +1271,9 @@ test "fmt.format" { |
| 1216 | 1271 | const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); |
| 1217 | 1272 | testing.expect(mem.eql(u8, result, "f64: 0.00000\n")); |
| 1218 | 1273 | } |
| 1219 | // libc checks | |
| 1274 | } | |
| 1275 | ||
| 1276 | test "fmt.float.libc.sanity" { | |
| 1220 | 1277 | { |
| 1221 | 1278 | var buf1: [32]u8 = undefined; |
| 1222 | 1279 | const value: f64 = f64(@bitCast(f32, u32(916964781))); |
| ... | ... | @@ -1267,127 +1324,127 @@ test "fmt.format" { |
| 1267 | 1324 | const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); |
| 1268 | 1325 | testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n")); |
| 1269 | 1326 | } |
| 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 | ||
| 1329 | test "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), | |
| 1293 | 1349 | else => unreachable, |
| 1294 | } | |
| 1350 | }, | |
| 1351 | else => unreachable, | |
| 1295 | 1352 | } |
| 1296 | }; | |
| 1353 | } | |
| 1354 | }; | |
| 1297 | 1355 | |
| 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); | |
| 1305 | 1363 | |
| 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 | } | |
| 1316 | 1368 | |
| 1317 | const inst = S{ | |
| 1318 | .a = 456, | |
| 1319 | .b = error.Unused, | |
| 1320 | }; | |
| 1369 | test "fmt.struct" { | |
| 1370 | const S = struct { | |
| 1371 | a: u32, | |
| 1372 | b: anyerror, | |
| 1373 | }; | |
| 1321 | 1374 | |
| 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 | }; | |
| 1330 | 1379 | |
| 1331 | const UU = union { | |
| 1332 | float: f32, | |
| 1333 | int: u32, | |
| 1334 | }; | |
| 1380 | try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst); | |
| 1381 | } | |
| 1335 | 1382 | |
| 1336 | const EU = extern union { | |
| 1337 | float: f32, | |
| 1338 | int: u32, | |
| 1339 | }; | |
| 1383 | test "fmt.union" { | |
| 1384 | const TU = union(enum) { | |
| 1385 | float: f32, | |
| 1386 | int: u32, | |
| 1387 | }; | |
| 1340 | 1388 | |
| 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 | }; | |
| 1344 | 1393 | |
| 1345 | try testFmt("TU{ .int = 123 }", "{}", tu_inst); | |
| 1394 | const EU = extern union { | |
| 1395 | float: f32, | |
| 1396 | int: u32, | |
| 1397 | }; | |
| 1346 | 1398 | |
| 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 }; | |
| 1350 | 1402 | |
| 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); | |
| 1361 | 1404 | |
| 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@")); | |
| 1363 | 1408 | |
| 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 | } | |
| 1372 | 1412 | |
| 1373 | var inst = S{ | |
| 1374 | .a = null, | |
| 1375 | }; | |
| 1376 | inst.a = &inst; | |
| 1413 | test "fmt.enum" { | |
| 1414 | const E = enum { | |
| 1415 | One, | |
| 1416 | Two, | |
| 1417 | Three, | |
| 1418 | }; | |
| 1377 | 1419 | |
| 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 | ||
| 1425 | test "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 | ||
| 1439 | test "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 | } |
| 1392 | 1449 | |
| 1393 | 1450 | fn 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 | 564 | }, |
| 565 | 565 | |
| 566 | 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), | |
| 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), | |
| 573 | 573 | |
| 574 | 574 | builtin.TypeId.BoundFn, |
| 575 | 575 | builtin.TypeId.ComptimeFloat, |
std/mem.zig+37| ... | ... | @@ -996,6 +996,43 @@ test "mem.join" { |
| 996 | 996 | testing.expect(eql(u8, try join(a, ",", [_][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c")); |
| 997 | 997 | } |
| 998 | 998 | |
| 999 | /// Copies each T from slices into a new slice that exactly holds all the elements. | |
| 1000 | pub 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 | ||
| 1024 | test "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 | ||
| 999 | 1036 | test "testStringEquality" { |
| 1000 | 1037 | testing.expect(eql(u8, "abcd", "abcd")); |
| 1001 | 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 | 632 | |
| 633 | 633 | pub const CreateProcessError = error{ |
| 634 | 634 | FileNotFound, |
| 635 | AccessDenied, | |
| 635 | 636 | InvalidName, |
| 636 | 637 | Unexpected, |
| 637 | 638 | }; |
| ... | ... | @@ -663,6 +664,7 @@ pub fn CreateProcessW( |
| 663 | 664 | switch (kernel32.GetLastError()) { |
| 664 | 665 | ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 665 | 666 | ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 667 | ERROR.ACCESS_DENIED => return error.AccessDenied, | |
| 666 | 668 | ERROR.INVALID_PARAMETER => unreachable, |
| 667 | 669 | ERROR.INVALID_NAME => return error.InvalidName, |
| 668 | 670 | else => |err| return unexpectedError(err), |
test/stage1/behavior/slice.zig+11| ... | ... | @@ -54,3 +54,14 @@ test "comptime slices are disambiguated" { |
| 54 | 54 | expect(sliceSum([_]u8{ 1, 2 }) == 3); |
| 55 | 55 | expect(sliceSum([_]u8{ 3, 4 }) == 7); |
| 56 | 56 | } |
| 57 | ||
| 58 | test "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 | const expect = @import("std").testing.expect; | |
| 2 | const mem = @import("std").mem; | |
| 3 | const TypeInfo = @import("builtin").TypeInfo; | |
| 4 | const TypeId = @import("builtin").TypeId; | |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | const mem = std.mem; | |
| 4 | const builtin = @import("builtin"); | |
| 5 | const TypeInfo = builtin.TypeInfo; | |
| 6 | const TypeId = builtin.TypeId; | |
| 5 | 7 | |
| 6 | 8 | test "type info: tag type, void info" { |
| 7 | 9 | testBasic(); |
| ... | ... | @@ -317,3 +319,20 @@ test "type info: TypeId -> TypeInfo impl cast" { |
| 317 | 319 | _ = passTypeInfo(TypeId.Void); |
| 318 | 320 | _ = comptime passTypeInfo(TypeId.Void); |
| 319 | 321 | } |
| 322 | ||
| 323 | test "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 | } |