| 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,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, ...) |
| 27 | Buf *buf_vprintf(const char *format, va_list ap); | 27 | Buf *buf_vprintf(const char *format, va_list ap); |
| 28 | 28 | ||
| 29 | static inline size_t buf_len(Buf *buf) { | 29 | static 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 | } |
| 33 | 34 | ||
| 34 | static inline char *buf_ptr(Buf *buf) { | 35 | static 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) { |
| 8732 | 8732 | ||
| 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"); |
| 8736 | 8737 | ||
| 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(); |
| 468 | 468 | ||
| 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); // placeholder | 472 | args.append(NULL); // placeholder |
| 472 | args.append(NULL); // placeholder | 473 | 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")); |
| 527 | 528 | ||
| 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); |
| 530 | 531 | ||
| 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); |
| 581 | 582 | ||
| 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) { |
| 1161 | 1164 | ||
| 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 | } |
| 1214 | 1217 | ||
| 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 | } |
| 1226 | 1222 | 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 | } |
| 107 | 107 | ||
| 108 | static void os_spawn_process_posix(const char *exe, ZigList<const char *> &args, Termination *term) { | 108 | static 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; | ||
| 115 | 114 | ||
| 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 | #endif | 125 | #endif |
| 127 | 126 | ||
| 128 | #if defined(ZIG_OS_WINDOWS) | 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 | 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 | } |
| 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 | 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); |
| 153 | 150 | ||
| 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); |
| 157 | 154 | ||
| 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); |
| 160 | 158 | ||
| ... | @@ -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 | #endif | 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 | #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 | #else | 179 | #else |
| 182 | #error "missing os_spawn_process implementation" | 180 | #error "missing os_spawn_process implementation" |
| 183 | #endif | 181 | #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 | } |
| 786 | 784 | ||
| 787 | #if defined(ZIG_OS_POSIX) | 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 | 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"); |
| 819 | 817 | ||
| 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 | //} |
| 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 | 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); |
| 882 | 879 | ||
| 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; |
| 927 | 924 | ||
| 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); |
| 930 | 928 | ||
| ... | @@ -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 | #endif | 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 | 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 | #else | 1013 | #else |
| 1016 | #error "missing os_exec_process implementation" | 1014 | #error "missing os_exec_process implementation" |
| 1017 | #endif | 1015 | #endif |
src/os.hpp+2-2| ... | @@ -100,8 +100,8 @@ struct OsFileAttr { | ... | @@ -100,8 +100,8 @@ struct OsFileAttr { |
| 100 | 100 | ||
| 101 | int os_init(void); | 101 | int os_init(void); |
| 102 | 102 | ||
| 103 | void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term); | 103 | void os_spawn_process(ZigList<const char *> &args, Termination *term); |
| 104 | Error os_exec_process(const char *exe, ZigList<const char *> &args, | 104 | Error 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); |
| 106 | Error os_execv(const char *exe, const char **argv); | 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,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 | } |
| 105 | 105 | ||
| 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 | }; |
| 173 | 173 | ||
| 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 | } |
| 204 | 211 | ||
| 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 { |
| 250 | 257 | ||
| 251 | test "std.atomic.Queue single-threaded" { | 258 | test "std.atomic.Queue single-threaded" { |
| 252 | var queue = Queue(i32).init(); | 259 | var queue = Queue(i32).init(); |
| 260 | expect(queue.isEmpty()); | ||
| 253 | 261 | ||
| 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()); | ||
| 260 | 269 | ||
| 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()); | ||
| 267 | 277 | ||
| 268 | expect(queue.get().?.data == 0); | 278 | expect(queue.get().?.data == 0); |
| 279 | expect(!queue.isEmpty()); | ||
| 269 | 280 | ||
| 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()); | ||
| 276 | 288 | ||
| 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()); | ||
| 283 | 296 | ||
| 284 | expect(queue.get().?.data == 1); | 297 | expect(queue.get().?.data == 1); |
| 298 | expect(!queue.isEmpty()); | ||
| 285 | 299 | ||
| 286 | expect(queue.get().?.data == 2); | 300 | expect(queue.get().?.data == 2); |
| 301 | expect(!queue.isEmpty()); | ||
| 287 | 302 | ||
| 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()); | ||
| 294 | 310 | ||
| 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()); | ||
| 297 | 314 | ||
| 298 | expect(queue.get().?.data == 4); | 315 | expect(queue.get().?.data == 4); |
| 316 | expect(queue.isEmpty()); | ||
| 299 | 317 | ||
| 300 | expect(queue.get() == null); | 318 | expect(queue.get() == null); |
| 319 | expect(queue.isEmpty()); | ||
| 301 | } | 320 | } |
| 302 | 321 | ||
| 303 | test "std.atomic.Queue dump" { | 322 | test "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 { |
| 543 | 543 | ||
| 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); | ||
| 546 | 548 | ||
| 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| { |
| 551 | 553 | 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 | |
| 554 | 556 | 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 | }; |
| 567 | 574 |
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; |
| 13 | pub const Sha3_384 = sha3.Sha3_384; | 13 | pub const Sha3_384 = sha3.Sha3_384; |
| 14 | pub const Sha3_512 = sha3.Sha3_512; | 14 | pub const Sha3_512 = sha3.Sha3_512; |
| 15 | 15 | ||
| 16 | pub const gimli = @import("crypto/gimli.zig"); | ||
| 17 | |||
| 16 | const blake2 = @import("crypto/blake2.zig"); | 18 | const blake2 = @import("crypto/blake2.zig"); |
| 17 | pub const Blake2s224 = blake2.Blake2s224; | 19 | pub const Blake2s224 = blake2.Blake2s224; |
| 18 | pub const Blake2s256 = blake2.Blake2s256; | 20 | pub const Blake2s256 = blake2.Blake2s256; |
| ... | @@ -38,6 +40,7 @@ pub const randomBytes = std.os.getrandom; | ... | @@ -38,6 +40,7 @@ pub const randomBytes = std.os.getrandom; |
| 38 | test "crypto" { | 40 | test "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 | |||
| 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,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` and | 14 | /// If `output` returns an error, the error is returned from `format` and |
| 15 | /// `output` is not called again. | 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 | 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), |
| 28 | 34 | ||
| 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 | } | ||
| 149 | 157 | ||
| 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 | } |
| 265 | 276 | ||
| 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 | } |
| 799 | 810 | ||
| 800 | test "fmt.parseInt" { | 811 | test "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 | } |
| 830 | 841 | ||
| 831 | test "fmt.parseUnsigned" { | 842 | test "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 | } |
| 915 | 926 | ||
| 916 | test "buf print int" { | 927 | test "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 | } |
| 951 | 962 | ||
| 952 | test "fmt.format" { | 963 | test "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 | |||
| 974 | test "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 | |||
| 985 | test "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 | |||
| 992 | test "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 | |||
| 1003 | test "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 | |||
| 1023 | test "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 | |||
| 1038 | test "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 | |||
| 1052 | test "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 | |
| 1068 | test "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 | |||
| 1073 | test "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 | |||
| 1078 | test "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, | 1097 | test "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 | |||
| 1107 | test "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 | |||
| 1139 | test "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 | |||
| 1168 | test "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 | |||
| 1193 | test "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 checks | 1274 | } |
| 1275 | |||
| 1276 | test "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 format | 1327 | } |
| 1271 | { | 1328 | |
| 1272 | const Vec2 = struct { | 1329 | test "fmt.custom" { |
| 1273 | const SelfType = @This(); | 1330 | const Vec2 = struct { |
| 1274 | x: f32, | 1331 | const SelfType = @This(); |
| 1275 | y: f32, | 1332 | x: f32, |
| 1276 | 1333 | 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 format | 1344 | 1 => switch (fmt[0]) { |
| 1288 | 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y), | 1345 | //point format |
| 1289 | //dimension format | 1346 | '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 | }; | ||
| 1297 | 1355 | ||
| 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); |
| 1305 | 1363 | ||
| 1306 | // same thing but not passing a pointer | 1364 | // 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 | }; | ||
| 1316 | 1368 | ||
| 1317 | const inst = S{ | 1369 | test "fmt.struct" { |
| 1318 | .a = 456, | 1370 | const S = struct { |
| 1319 | .b = error.Unused, | 1371 | a: u32, |
| 1320 | }; | 1372 | b: anyerror, |
| 1373 | }; | ||
| 1321 | 1374 | ||
| 1322 | try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst); | 1375 | const inst = S{ |
| 1323 | } | 1376 | .a = 456, |
| 1324 | //union format | 1377 | .b = error.Unused, |
| 1325 | { | 1378 | }; |
| 1326 | const TU = union(enum) { | ||
| 1327 | float: f32, | ||
| 1328 | int: u32, | ||
| 1329 | }; | ||
| 1330 | 1379 | ||
| 1331 | const UU = union { | 1380 | try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst); |
| 1332 | float: f32, | 1381 | } |
| 1333 | int: u32, | ||
| 1334 | }; | ||
| 1335 | 1382 | ||
| 1336 | const EU = extern union { | 1383 | test "fmt.union" { |
| 1337 | float: f32, | 1384 | const TU = union(enum) { |
| 1338 | int: u32, | 1385 | float: f32, |
| 1339 | }; | 1386 | int: u32, |
| 1387 | }; | ||
| 1340 | 1388 | ||
| 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 | }; | ||
| 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; | 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 }; |
| 1350 | 1402 | ||
| 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 | }; | ||
| 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); | 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 format | 1411 | } |
| 1367 | { | ||
| 1368 | const S = struct { | ||
| 1369 | const SelfType = @This(); | ||
| 1370 | a: ?*SelfType, | ||
| 1371 | }; | ||
| 1372 | 1412 | ||
| 1373 | var inst = S{ | 1413 | test "fmt.enum" { |
| 1374 | .a = null, | 1414 | const E = enum { |
| 1375 | }; | 1415 | One, |
| 1376 | inst.a = &inst; | 1416 | Two, |
| 1417 | Three, | ||
| 1418 | }; | ||
| 1377 | 1419 | ||
| 1378 | try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst); | 1420 | const inst = E.Two; |
| 1379 | } | 1421 | |
| 1380 | //print bytes as hex | 1422 | 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); | 1425 | test "fmt.struct.self-referential" { |
| 1384 | try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes); | 1426 | const S = struct { |
| 1385 | //Test Slices | 1427 | 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 | |||
| 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 | fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void { | 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,12 +564,12 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type |
| 564 | }, | 564 | }, |
| 565 | 565 | ||
| 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), |
| 573 | 573 | ||
| 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 | } |
| 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 | test "testStringEquality" { | 1036 | test "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 |
| 632 | 632 | ||
| 633 | pub const CreateProcessError = error{ | 633 | pub 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 | |||
| 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,7 +1,9 @@ |
| 1 | const expect = @import("std").testing.expect; | 1 | const std = @import("std"); |
| 2 | const mem = @import("std").mem; | 2 | const expect = std.testing.expect; |
| 3 | const TypeInfo = @import("builtin").TypeInfo; | 3 | const mem = std.mem; |
| 4 | const TypeId = @import("builtin").TypeId; | 4 | const builtin = @import("builtin"); |
| 5 | const TypeInfo = builtin.TypeInfo; | ||
| 6 | const TypeId = builtin.TypeId; | ||
| 5 | 7 | ||
| 6 | test "type info: tag type, void info" { | 8 | test "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 | |||
| 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 | } |