| author | |
| committer | |
| log | 2b42e910bf4696032158cc7ae268d3c69d699f70 |
| tree | d00255e0c8d3a857e62777524f4271edbaa69c75 |
| parent | 44a049e01eef654fee82a1ee4e1aaf37447319ce |
| signature |
13 files changed, 119 insertions(+), 81 deletions(-)
std/c.zig+6-3| ... | @@ -1,4 +1,6 @@ | ... | @@ -1,4 +1,6 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("std"); | ||
| 3 | const page_size = std.mem.page_size; | ||
| 2 | 4 | ||
| 3 | pub use @import("os/bits.zig"); | 5 | pub use @import("os/bits.zig"); |
| 4 | 6 | ||
| ... | @@ -33,7 +35,7 @@ pub extern "c" fn close(fd: fd_t) c_int; | ... | @@ -33,7 +35,7 @@ pub extern "c" fn close(fd: fd_t) c_int; |
| 33 | pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; | 35 | pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; |
| 34 | pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int; | 36 | pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int; |
| 35 | pub extern "c" fn lseek(fd: fd_t, offset: isize, whence: c_int) isize; | 37 | pub extern "c" fn lseek(fd: fd_t, offset: isize, whence: c_int) isize; |
| 36 | pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int; | 38 | pub extern "c" fn open(path: [*]const u8, oflag: c_uint, ...) c_int; |
| 37 | pub extern "c" fn raise(sig: c_int) c_int; | 39 | pub extern "c" fn raise(sig: c_int) c_int; |
| 38 | pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; | 40 | pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; |
| 39 | pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize; | 41 | pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize; |
| ... | @@ -42,8 +44,9 @@ pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec, iovcnt: c_int, offset: | ... | @@ -42,8 +44,9 @@ pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec, iovcnt: c_int, offset: |
| 42 | pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; | 44 | pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; |
| 43 | pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize; | 45 | pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize; |
| 44 | pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize; | 46 | pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize; |
| 45 | pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: fd_t, offset: isize) usize; | 47 | pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: isize) *c_void; |
| 46 | pub extern "c" fn munmap(addr: ?*c_void, len: usize) c_int; | 48 | pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int; |
| 49 | pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int; | ||
| 47 | pub extern "c" fn unlink(path: [*]const u8) c_int; | 50 | pub extern "c" fn unlink(path: [*]const u8) c_int; |
| 48 | pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; | 51 | pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; |
| 49 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int; | 52 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int; |
std/debug.zig+3-4| ... | @@ -1011,7 +1011,7 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo { | ... | @@ -1011,7 +1011,7 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo { |
| 1011 | S.self_exe_file = try fs.openSelfExe(); | 1011 | S.self_exe_file = try fs.openSelfExe(); |
| 1012 | errdefer S.self_exe_file.close(); | 1012 | errdefer S.self_exe_file.close(); |
| 1013 | 1013 | ||
| 1014 | const self_exe_mmap_len = try S.self_exe_file.getEndPos(); | 1014 | const self_exe_mmap_len = mem.alignForward(try S.self_exe_file.getEndPos(), mem.page_size); |
| 1015 | const self_exe_mmap = try os.mmap( | 1015 | const self_exe_mmap = try os.mmap( |
| 1016 | null, | 1016 | null, |
| 1017 | self_exe_mmap_len, | 1017 | self_exe_mmap_len, |
| ... | @@ -1020,10 +1020,9 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo { | ... | @@ -1020,10 +1020,9 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo { |
| 1020 | S.self_exe_file.handle, | 1020 | S.self_exe_file.handle, |
| 1021 | 0, | 1021 | 0, |
| 1022 | ); | 1022 | ); |
| 1023 | errdefer os.munmap(self_exe_mmap, self_exe_mmap_len); | 1023 | errdefer os.munmap(self_exe_mmap); |
| 1024 | 1024 | ||
| 1025 | const file_mmap_slice = @intToPtr([*]const u8, self_exe_mmap)[0..self_exe_mmap_len]; | 1025 | S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(self_exe_mmap); |
| 1026 | S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(file_mmap_slice); | ||
| 1027 | 1026 | ||
| 1028 | return openElfDebugInfo( | 1027 | return openElfDebugInfo( |
| 1029 | allocator, | 1028 | allocator, |
std/fs.zig+2-2| ... | @@ -595,8 +595,8 @@ pub const Dir = struct { | ... | @@ -595,8 +595,8 @@ pub const Dir = struct { |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | while (true) { | 597 | while (true) { |
| 598 | const rc = os.system.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len); | 598 | const rc = os.linux.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len); |
| 599 | switch (os.errno(rc)) { | 599 | switch (os.linux.getErrno(rc)) { |
| 600 | 0 => {}, | 600 | 0 => {}, |
| 601 | os.EBADF => unreachable, | 601 | os.EBADF => unreachable, |
| 602 | os.EFAULT => unreachable, | 602 | os.EFAULT => unreachable, |
std/heap.zig+16-13| ... | @@ -104,35 +104,36 @@ pub const DirectAllocator = struct { | ... | @@ -104,35 +104,36 @@ pub const DirectAllocator = struct { |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | const alloc_size = if (alignment <= mem.page_size) n else n + alignment; | 106 | const alloc_size = if (alignment <= mem.page_size) n else n + alignment; |
| 107 | const addr = os.mmap( | 107 | const slice = os.mmap( |
| 108 | null, | 108 | null, |
| 109 | alloc_size, | 109 | mem.alignForward(alloc_size, mem.page_size), |
| 110 | os.PROT_READ | os.PROT_WRITE, | 110 | os.PROT_READ | os.PROT_WRITE, |
| 111 | os.MAP_PRIVATE | os.MAP_ANONYMOUS, | 111 | os.MAP_PRIVATE | os.MAP_ANONYMOUS, |
| 112 | -1, | 112 | -1, |
| 113 | 0, | 113 | 0, |
| 114 | ) catch return error.OutOfMemory; | 114 | ) catch return error.OutOfMemory; |
| 115 | if (alloc_size == n) return @intToPtr([*]u8, addr)[0..n]; | 115 | if (alloc_size == n) return slice; |
| 116 | 116 | ||
| 117 | const aligned_addr = mem.alignForward(addr, alignment); | 117 | const aligned_addr = mem.alignForward(@ptrToInt(slice.ptr), alignment); |
| 118 | 118 | ||
| 119 | // Unmap the extra bytes that were only requested in order to guarantee | 119 | // Unmap the extra bytes that were only requested in order to guarantee |
| 120 | // that the range of memory we were provided had a proper alignment in | 120 | // that the range of memory we were provided had a proper alignment in |
| 121 | // it somewhere. The extra bytes could be at the beginning, or end, or both. | 121 | // it somewhere. The extra bytes could be at the beginning, or end, or both. |
| 122 | const unused_start_len = aligned_addr - addr; | 122 | const unused_start_len = aligned_addr - @ptrToInt(slice.ptr); |
| 123 | if (unused_start_len != 0) { | 123 | if (unused_start_len != 0) { |
| 124 | os.munmap(addr, unused_start_len); | 124 | os.munmap(slice[0..unused_start_len]); |
| 125 | } | 125 | } |
| 126 | const aligned_end_addr = std.mem.alignForward(aligned_addr + n, mem.page_size); | 126 | const aligned_end_addr = mem.alignForward(aligned_addr + n, mem.page_size); |
| 127 | const unused_end_len = addr + alloc_size - aligned_end_addr; | 127 | const unused_end_len = @ptrToInt(slice.ptr) + slice.len - aligned_end_addr; |
| 128 | if (unused_end_len != 0) { | 128 | if (unused_end_len != 0) { |
| 129 | os.munmap(aligned_end_addr, unused_end_len); | 129 | os.munmap(@intToPtr([*]align(mem.page_size) u8, aligned_end_addr)[0..unused_end_len]); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | return @intToPtr([*]u8, aligned_addr)[0..n]; | 132 | return @intToPtr([*]u8, aligned_addr)[0..n]; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { | 135 | fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { |
| 136 | const old_mem = @alignCast(mem.page_size, old_mem_unaligned); | ||
| 136 | if (os.windows.is_the_target) { | 137 | if (os.windows.is_the_target) { |
| 137 | const w = os.windows; | 138 | const w = os.windows; |
| 138 | if (new_size == 0) { | 139 | if (new_size == 0) { |
| ... | @@ -165,12 +166,14 @@ pub const DirectAllocator = struct { | ... | @@ -165,12 +166,14 @@ pub const DirectAllocator = struct { |
| 165 | const new_addr_end = base_addr + new_size; | 166 | const new_addr_end = base_addr + new_size; |
| 166 | const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size); | 167 | const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size); |
| 167 | if (old_addr_end > new_addr_end_rounded) { | 168 | if (old_addr_end > new_addr_end_rounded) { |
| 168 | os.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded); | 169 | const ptr = @intToPtr([*]align(mem.page_size) u8, new_addr_end_rounded); |
| 170 | os.munmap(ptr[0 .. old_addr_end - new_addr_end_rounded]); | ||
| 169 | } | 171 | } |
| 170 | return old_mem[0..new_size]; | 172 | return old_mem[0..new_size]; |
| 171 | } | 173 | } |
| 172 | 174 | ||
| 173 | fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { | 175 | fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { |
| 176 | const old_mem = @alignCast(mem.page_size, old_mem_unaligned); | ||
| 174 | if (os.windows.is_the_target) { | 177 | if (os.windows.is_the_target) { |
| 175 | if (old_mem.len == 0) { | 178 | if (old_mem.len == 0) { |
| 176 | return alloc(allocator, new_size, new_align); | 179 | return alloc(allocator, new_size, new_align); |
| ... | @@ -231,7 +234,7 @@ pub const DirectAllocator = struct { | ... | @@ -231,7 +234,7 @@ pub const DirectAllocator = struct { |
| 231 | const result = try alloc(allocator, new_size, new_align); | 234 | const result = try alloc(allocator, new_size, new_align); |
| 232 | if (old_mem.len != 0) { | 235 | if (old_mem.len != 0) { |
| 233 | @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len)); | 236 | @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len)); |
| 234 | os.munmap(@ptrToInt(old_mem.ptr), old_mem.len); | 237 | os.munmap(old_mem); |
| 235 | } | 238 | } |
| 236 | return result; | 239 | return result; |
| 237 | } | 240 | } |
std/io.zig+3-3| ... | @@ -1,12 +1,12 @@ | ... | @@ -1,12 +1,12 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const Os = builtin.Os; | ||
| 4 | const c = std.c; | 3 | const c = std.c; |
| 5 | 4 | ||
| 6 | const math = std.math; | 5 | const math = std.math; |
| 7 | const debug = std.debug; | 6 | const debug = std.debug; |
| 8 | const assert = debug.assert; | 7 | const assert = debug.assert; |
| 9 | const os = std.os; | 8 | const os = std.os; |
| 9 | const fs = std.fs; | ||
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const meta = std.meta; | 11 | const meta = std.meta; |
| 12 | const trait = meta.trait; | 12 | const trait = meta.trait; |
| ... | @@ -985,7 +985,7 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { | ... | @@ -985,7 +985,7 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { |
| 985 | } | 985 | } |
| 986 | 986 | ||
| 987 | pub const BufferedAtomicFile = struct { | 987 | pub const BufferedAtomicFile = struct { |
| 988 | atomic_file: os.AtomicFile, | 988 | atomic_file: fs.AtomicFile, |
| 989 | file_stream: File.OutStream, | 989 | file_stream: File.OutStream, |
| 990 | buffered_stream: BufferedOutStream(File.WriteError), | 990 | buffered_stream: BufferedOutStream(File.WriteError), |
| 991 | allocator: *mem.Allocator, | 991 | allocator: *mem.Allocator, |
| ... | @@ -1001,7 +1001,7 @@ pub const BufferedAtomicFile = struct { | ... | @@ -1001,7 +1001,7 @@ pub const BufferedAtomicFile = struct { |
| 1001 | }; | 1001 | }; |
| 1002 | errdefer allocator.destroy(self); | 1002 | errdefer allocator.destroy(self); |
| 1003 | 1003 | ||
| 1004 | self.atomic_file = try os.AtomicFile.init(dest_path, File.default_mode); | 1004 | self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode); |
| 1005 | errdefer self.atomic_file.deinit(); | 1005 | errdefer self.atomic_file.deinit(); |
| 1006 | 1006 | ||
| 1007 | self.file_stream = self.atomic_file.file.outStream(); | 1007 | self.file_stream = self.atomic_file.file.outStream(); |
std/io/c_out_stream.zig+1-1| ... | @@ -37,7 +37,7 @@ pub const COutStream = struct { | ... | @@ -37,7 +37,7 @@ pub const COutStream = struct { |
| 37 | os.ENOSPC => return error.NoSpaceLeft, | 37 | os.ENOSPC => return error.NoSpaceLeft, |
| 38 | os.EPERM => return error.AccessDenied, | 38 | os.EPERM => return error.AccessDenied, |
| 39 | os.EPIPE => return error.BrokenPipe, | 39 | os.EPIPE => return error.BrokenPipe, |
| 40 | else => return os.unexpectedErrno(@intCast(usize, errno)), | 40 | else => |err| return os.unexpectedErrno(@intCast(usize, err)), |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
| 43 | }; | 43 | }; |
std/mem.zig+50-23| ... | @@ -585,14 +585,14 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) | ... | @@ -585,14 +585,14 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) |
| 585 | test "comptime read/write int" { | 585 | test "comptime read/write int" { |
| 586 | comptime { | 586 | comptime { |
| 587 | var bytes: [2]u8 = undefined; | 587 | var bytes: [2]u8 = undefined; |
| 588 | std.mem.writeIntLittle(u16, &bytes, 0x1234); | 588 | writeIntLittle(u16, &bytes, 0x1234); |
| 589 | const result = std.mem.readIntBig(u16, &bytes); | 589 | const result = readIntBig(u16, &bytes); |
| 590 | testing.expect(result == 0x3412); | 590 | testing.expect(result == 0x3412); |
| 591 | } | 591 | } |
| 592 | comptime { | 592 | comptime { |
| 593 | var bytes: [2]u8 = undefined; | 593 | var bytes: [2]u8 = undefined; |
| 594 | std.mem.writeIntBig(u16, &bytes, 0x1234); | 594 | writeIntBig(u16, &bytes, 0x1234); |
| 595 | const result = std.mem.readIntLittle(u16, &bytes); | 595 | const result = readIntLittle(u16, &bytes); |
| 596 | testing.expect(result == 0x3412); | 596 | testing.expect(result == 0x3412); |
| 597 | } | 597 | } |
| 598 | } | 598 | } |
| ... | @@ -1053,7 +1053,7 @@ fn testReadIntImpl() void { | ... | @@ -1053,7 +1053,7 @@ fn testReadIntImpl() void { |
| 1053 | } | 1053 | } |
| 1054 | } | 1054 | } |
| 1055 | 1055 | ||
| 1056 | test "std.mem.writeIntSlice" { | 1056 | test "writeIntSlice" { |
| 1057 | testWriteIntImpl(); | 1057 | testWriteIntImpl(); |
| 1058 | comptime testWriteIntImpl(); | 1058 | comptime testWriteIntImpl(); |
| 1059 | } | 1059 | } |
| ... | @@ -1184,7 +1184,7 @@ pub fn reverse(comptime T: type, items: []T) void { | ... | @@ -1184,7 +1184,7 @@ pub fn reverse(comptime T: type, items: []T) void { |
| 1184 | } | 1184 | } |
| 1185 | } | 1185 | } |
| 1186 | 1186 | ||
| 1187 | test "std.mem.reverse" { | 1187 | test "reverse" { |
| 1188 | var arr = []i32{ | 1188 | var arr = []i32{ |
| 1189 | 5, | 1189 | 5, |
| 1190 | 3, | 1190 | 3, |
| ... | @@ -1211,7 +1211,7 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void { | ... | @@ -1211,7 +1211,7 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void { |
| 1211 | reverse(T, items); | 1211 | reverse(T, items); |
| 1212 | } | 1212 | } |
| 1213 | 1213 | ||
| 1214 | test "std.mem.rotate" { | 1214 | test "rotate" { |
| 1215 | var arr = []i32{ | 1215 | var arr = []i32{ |
| 1216 | 5, | 1216 | 5, |
| 1217 | 3, | 1217 | 3, |
| ... | @@ -1296,14 +1296,14 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@typeOf(ptr)) { | ... | @@ -1296,14 +1296,14 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@typeOf(ptr)) { |
| 1296 | return @ptrCast(AsBytesReturnType(P), ptr); | 1296 | return @ptrCast(AsBytesReturnType(P), ptr); |
| 1297 | } | 1297 | } |
| 1298 | 1298 | ||
| 1299 | test "std.mem.asBytes" { | 1299 | test "asBytes" { |
| 1300 | const deadbeef = u32(0xDEADBEEF); | 1300 | const deadbeef = u32(0xDEADBEEF); |
| 1301 | const deadbeef_bytes = switch (builtin.endian) { | 1301 | const deadbeef_bytes = switch (builtin.endian) { |
| 1302 | builtin.Endian.Big => "\xDE\xAD\xBE\xEF", | 1302 | builtin.Endian.Big => "\xDE\xAD\xBE\xEF", |
| 1303 | builtin.Endian.Little => "\xEF\xBE\xAD\xDE", | 1303 | builtin.Endian.Little => "\xEF\xBE\xAD\xDE", |
| 1304 | }; | 1304 | }; |
| 1305 | 1305 | ||
| 1306 | testing.expect(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes)); | 1306 | testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes)); |
| 1307 | 1307 | ||
| 1308 | var codeface = u32(0xC0DEFACE); | 1308 | var codeface = u32(0xC0DEFACE); |
| 1309 | for (asBytes(&codeface).*) |*b| | 1309 | for (asBytes(&codeface).*) |*b| |
| ... | @@ -1323,7 +1323,7 @@ test "std.mem.asBytes" { | ... | @@ -1323,7 +1323,7 @@ test "std.mem.asBytes" { |
| 1323 | .c = 0xDE, | 1323 | .c = 0xDE, |
| 1324 | .d = 0xA1, | 1324 | .d = 0xA1, |
| 1325 | }; | 1325 | }; |
| 1326 | testing.expect(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); | 1326 | testing.expect(eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); |
| 1327 | } | 1327 | } |
| 1328 | 1328 | ||
| 1329 | ///Given any value, returns a copy of its bytes in an array. | 1329 | ///Given any value, returns a copy of its bytes in an array. |
| ... | @@ -1331,17 +1331,17 @@ pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8 { | ... | @@ -1331,17 +1331,17 @@ pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8 { |
| 1331 | return asBytes(&value).*; | 1331 | return asBytes(&value).*; |
| 1332 | } | 1332 | } |
| 1333 | 1333 | ||
| 1334 | test "std.mem.toBytes" { | 1334 | test "toBytes" { |
| 1335 | var my_bytes = toBytes(u32(0x12345678)); | 1335 | var my_bytes = toBytes(u32(0x12345678)); |
| 1336 | switch (builtin.endian) { | 1336 | switch (builtin.endian) { |
| 1337 | builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")), | 1337 | builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x12\x34\x56\x78")), |
| 1338 | builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")), | 1338 | builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x78\x56\x34\x12")), |
| 1339 | } | 1339 | } |
| 1340 | 1340 | ||
| 1341 | my_bytes[0] = '\x99'; | 1341 | my_bytes[0] = '\x99'; |
| 1342 | switch (builtin.endian) { | 1342 | switch (builtin.endian) { |
| 1343 | builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")), | 1343 | builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x99\x34\x56\x78")), |
| 1344 | builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")), | 1344 | builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x99\x56\x34\x12")), |
| 1345 | } | 1345 | } |
| 1346 | } | 1346 | } |
| 1347 | 1347 | ||
| ... | @@ -1363,7 +1363,7 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typ | ... | @@ -1363,7 +1363,7 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typ |
| 1363 | return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)), bytes); | 1363 | return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)), bytes); |
| 1364 | } | 1364 | } |
| 1365 | 1365 | ||
| 1366 | test "std.mem.bytesAsValue" { | 1366 | test "bytesAsValue" { |
| 1367 | const deadbeef = u32(0xDEADBEEF); | 1367 | const deadbeef = u32(0xDEADBEEF); |
| 1368 | const deadbeef_bytes = switch (builtin.endian) { | 1368 | const deadbeef_bytes = switch (builtin.endian) { |
| 1369 | builtin.Endian.Big => "\xDE\xAD\xBE\xEF", | 1369 | builtin.Endian.Big => "\xDE\xAD\xBE\xEF", |
| ... | @@ -1405,7 +1405,7 @@ test "std.mem.bytesAsValue" { | ... | @@ -1405,7 +1405,7 @@ test "std.mem.bytesAsValue" { |
| 1405 | pub fn bytesToValue(comptime T: type, bytes: var) T { | 1405 | pub fn bytesToValue(comptime T: type, bytes: var) T { |
| 1406 | return bytesAsValue(T, &bytes).*; | 1406 | return bytesAsValue(T, &bytes).*; |
| 1407 | } | 1407 | } |
| 1408 | test "std.mem.bytesToValue" { | 1408 | test "bytesToValue" { |
| 1409 | const deadbeef_bytes = switch (builtin.endian) { | 1409 | const deadbeef_bytes = switch (builtin.endian) { |
| 1410 | builtin.Endian.Big => "\xDE\xAD\xBE\xEF", | 1410 | builtin.Endian.Big => "\xDE\xAD\xBE\xEF", |
| 1411 | builtin.Endian.Little => "\xEF\xBE\xAD\xDE", | 1411 | builtin.Endian.Little => "\xEF\xBE\xAD\xDE", |
| ... | @@ -1430,25 +1430,25 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA | ... | @@ -1430,25 +1430,25 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA |
| 1430 | return @ptrCast(ReturnType, &ptr[start]); | 1430 | return @ptrCast(ReturnType, &ptr[start]); |
| 1431 | } | 1431 | } |
| 1432 | 1432 | ||
| 1433 | test "std.mem.subArrayPtr" { | 1433 | test "subArrayPtr" { |
| 1434 | const a1 = "abcdef"; | 1434 | const a1 = "abcdef"; |
| 1435 | const sub1 = subArrayPtr(&a1, 2, 3); | 1435 | const sub1 = subArrayPtr(&a1, 2, 3); |
| 1436 | testing.expect(std.mem.eql(u8, sub1.*, "cde")); | 1436 | testing.expect(eql(u8, sub1.*, "cde")); |
| 1437 | 1437 | ||
| 1438 | var a2 = "abcdef"; | 1438 | var a2 = "abcdef"; |
| 1439 | var sub2 = subArrayPtr(&a2, 2, 3); | 1439 | var sub2 = subArrayPtr(&a2, 2, 3); |
| 1440 | 1440 | ||
| 1441 | testing.expect(std.mem.eql(u8, sub2, "cde")); | 1441 | testing.expect(eql(u8, sub2, "cde")); |
| 1442 | sub2[1] = 'X'; | 1442 | sub2[1] = 'X'; |
| 1443 | testing.expect(std.mem.eql(u8, a2, "abcXef")); | 1443 | testing.expect(eql(u8, a2, "abcXef")); |
| 1444 | } | 1444 | } |
| 1445 | 1445 | ||
| 1446 | /// Round an address up to the nearest aligned address | 1446 | /// Round an address up to the nearest aligned address |
| 1447 | pub fn alignForward(addr: usize, alignment: usize) usize { | 1447 | pub fn alignForward(addr: usize, alignment: usize) usize { |
| 1448 | return (addr + alignment - 1) & ~(alignment - 1); | 1448 | return alignBackward(addr + (alignment - 1), alignment); |
| 1449 | } | 1449 | } |
| 1450 | 1450 | ||
| 1451 | test "std.mem.alignForward" { | 1451 | test "alignForward" { |
| 1452 | testing.expect(alignForward(1, 1) == 1); | 1452 | testing.expect(alignForward(1, 1) == 1); |
| 1453 | testing.expect(alignForward(2, 1) == 2); | 1453 | testing.expect(alignForward(2, 1) == 2); |
| 1454 | testing.expect(alignForward(1, 2) == 2); | 1454 | testing.expect(alignForward(1, 2) == 2); |
| ... | @@ -1462,3 +1462,30 @@ test "std.mem.alignForward" { | ... | @@ -1462,3 +1462,30 @@ test "std.mem.alignForward" { |
| 1462 | testing.expect(alignForward(16, 8) == 16); | 1462 | testing.expect(alignForward(16, 8) == 16); |
| 1463 | testing.expect(alignForward(17, 8) == 24); | 1463 | testing.expect(alignForward(17, 8) == 24); |
| 1464 | } | 1464 | } |
| 1465 | |||
| 1466 | pub fn alignBackward(addr: usize, alignment: usize) usize { | ||
| 1467 | // 000010000 // example addr | ||
| 1468 | // 000001111 // subtract 1 | ||
| 1469 | // 111110000 // binary not | ||
| 1470 | return addr & ~(alignment - 1); | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | pub fn isAligned(addr: usize, alignment: usize) bool { | ||
| 1474 | return alignBackward(addr, alignment) == addr; | ||
| 1475 | } | ||
| 1476 | |||
| 1477 | test "isAligned" { | ||
| 1478 | testing.expect(isAligned(0, 4)); | ||
| 1479 | testing.expect(isAligned(1, 1)); | ||
| 1480 | testing.expect(isAligned(2, 1)); | ||
| 1481 | testing.expect(isAligned(2, 2)); | ||
| 1482 | testing.expect(!isAligned(2, 4)); | ||
| 1483 | testing.expect(isAligned(3, 1)); | ||
| 1484 | testing.expect(!isAligned(3, 2)); | ||
| 1485 | testing.expect(!isAligned(3, 4)); | ||
| 1486 | testing.expect(isAligned(4, 4)); | ||
| 1487 | testing.expect(isAligned(4, 2)); | ||
| 1488 | testing.expect(isAligned(4, 1)); | ||
| 1489 | testing.expect(!isAligned(4, 8)); | ||
| 1490 | testing.expect(!isAligned(4, 16)); | ||
| 1491 | } |
std/os.zig+27-21| ... | @@ -251,7 +251,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | ... | @@ -251,7 +251,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 251 | // Linux can return EINVAL when read amount is > 0x7ffff000 | 251 | // Linux can return EINVAL when read amount is > 0x7ffff000 |
| 252 | // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274 | 252 | // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274 |
| 253 | // TODO audit this. Shawn Landden says that this is not actually true. | 253 | // TODO audit this. Shawn Landden says that this is not actually true. |
| 254 | // if this logic should stay, move it to std.os.linux.sys | 254 | // if this logic should stay, move it to std.os.linux |
| 255 | const max_buf_len = 0x7ffff000; | 255 | const max_buf_len = 0x7ffff000; |
| 256 | 256 | ||
| 257 | var index: usize = 0; | 257 | var index: usize = 0; |
| ... | @@ -260,8 +260,9 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | ... | @@ -260,8 +260,9 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 260 | const rc = system.read(fd, buf.ptr + index, want_to_read); | 260 | const rc = system.read(fd, buf.ptr + index, want_to_read); |
| 261 | switch (errno(rc)) { | 261 | switch (errno(rc)) { |
| 262 | 0 => { | 262 | 0 => { |
| 263 | index += rc; | 263 | const amt_read = @intCast(usize, rc); |
| 264 | if (rc == want_to_read) continue; | 264 | index += amt_read; |
| 265 | if (amt_read == want_to_read) continue; | ||
| 265 | // Read returned less than buf.len. | 266 | // Read returned less than buf.len. |
| 266 | return index; | 267 | return index; |
| 267 | }, | 268 | }, |
| ... | @@ -374,7 +375,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { | ... | @@ -374,7 +375,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { |
| 374 | // Linux can return EINVAL when write amount is > 0x7ffff000 | 375 | // Linux can return EINVAL when write amount is > 0x7ffff000 |
| 375 | // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856 | 376 | // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856 |
| 376 | // TODO audit this. Shawn Landden says that this is not actually true. | 377 | // TODO audit this. Shawn Landden says that this is not actually true. |
| 377 | // if this logic should stay, move it to std.os.linux.sys | 378 | // if this logic should stay, move it to std.os.linux |
| 378 | const max_bytes_len = 0x7ffff000; | 379 | const max_bytes_len = 0x7ffff000; |
| 379 | 380 | ||
| 380 | var index: usize = 0; | 381 | var index: usize = 0; |
| ... | @@ -383,7 +384,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { | ... | @@ -383,7 +384,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { |
| 383 | const rc = system.write(fd, bytes.ptr + index, amt_to_write); | 384 | const rc = system.write(fd, bytes.ptr + index, amt_to_write); |
| 384 | switch (errno(rc)) { | 385 | switch (errno(rc)) { |
| 385 | 0 => { | 386 | 0 => { |
| 386 | index += rc; | 387 | index += @intCast(usize, rc); |
| 387 | continue; | 388 | continue; |
| 388 | }, | 389 | }, |
| 389 | EINTR => continue, | 390 | EINTR => continue, |
| ... | @@ -1863,14 +1864,10 @@ pub const MProtectError = error{ | ... | @@ -1863,14 +1864,10 @@ pub const MProtectError = error{ |
| 1863 | Unexpected, | 1864 | Unexpected, |
| 1864 | }; | 1865 | }; |
| 1865 | 1866 | ||
| 1866 | /// address and length must be page-aligned | 1867 | /// `memory.len` must be page-aligned. |
| 1867 | pub fn mprotect(address: usize, length: usize, protection: u32) MProtectError!void { | 1868 | pub fn mprotect(memory: [*]align(mem.page_size) u8, protection: u32) MProtectError!void { |
| 1868 | const negative_page_size = @bitCast(usize, -isize(mem.page_size)); | 1869 | assert(mem.isAligned(memory.len, mem.page_size)); |
| 1869 | const aligned_address = address & negative_page_size; | 1870 | switch (errno(system.mprotect(memory.ptr, memory.len, protection))) { |
| 1870 | const aligned_end = (address + length + mem.page_size - 1) & negative_page_size; | ||
| 1871 | assert(address == aligned_address); | ||
| 1872 | assert(length == aligned_end - aligned_address); | ||
| 1873 | switch (errno(system.mprotect(address, length, protection))) { | ||
| 1874 | 0 => return, | 1871 | 0 => return, |
| 1875 | EINVAL => unreachable, | 1872 | EINVAL => unreachable, |
| 1876 | EACCES => return error.AccessDenied, | 1873 | EACCES => return error.AccessDenied, |
| ... | @@ -1906,17 +1903,26 @@ pub const MMapError = error{ | ... | @@ -1906,17 +1903,26 @@ pub const MMapError = error{ |
| 1906 | 1903 | ||
| 1907 | /// Map files or devices into memory. | 1904 | /// Map files or devices into memory. |
| 1908 | /// Use of a mapped region can result in these signals: | 1905 | /// Use of a mapped region can result in these signals: |
| 1906 | /// `length` must be page-aligned. | ||
| 1909 | /// * SIGSEGV - Attempted write into a region mapped as read-only. | 1907 | /// * SIGSEGV - Attempted write into a region mapped as read-only. |
| 1910 | /// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file | 1908 | /// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file |
| 1911 | pub fn mmap(address: ?[*]u8, length: usize, prot: u32, flags: u32, fd: fd_t, offset: isize) MMapError!usize { | 1909 | pub fn mmap( |
| 1910 | ptr: ?[*]align(mem.page_size) u8, | ||
| 1911 | length: usize, | ||
| 1912 | prot: u32, | ||
| 1913 | flags: u32, | ||
| 1914 | fd: fd_t, | ||
| 1915 | offset: isize, | ||
| 1916 | ) MMapError![]align(mem.page_size) u8 { | ||
| 1917 | assert(mem.isAligned(length, mem.page_size)); | ||
| 1912 | const err = if (builtin.link_libc) blk: { | 1918 | const err = if (builtin.link_libc) blk: { |
| 1913 | const rc = system.mmap(address, length, prot, flags, fd, offset); | 1919 | const rc = std.c.mmap(ptr, length, prot, flags, fd, offset); |
| 1914 | if (rc != system.MMAP_FAILED) return rc; | 1920 | if (rc != MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length]; |
| 1915 | break :blk system._errno().*; | 1921 | break :blk @intCast(usize, system._errno().*); |
| 1916 | } else blk: { | 1922 | } else blk: { |
| 1917 | const rc = system.mmap(address, length, prot, flags, fd, offset); | 1923 | const rc = system.mmap(ptr, length, prot, flags, fd, offset); |
| 1918 | const err = errno(rc); | 1924 | const err = errno(rc); |
| 1919 | if (err == 0) return rc; | 1925 | if (err == 0) return @intToPtr([*]align(mem.page_size) u8, rc)[0..length]; |
| 1920 | break :blk err; | 1926 | break :blk err; |
| 1921 | }; | 1927 | }; |
| 1922 | switch (err) { | 1928 | switch (err) { |
| ... | @@ -1940,8 +1946,8 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: u32, flags: u32, fd: fd_t, off | ... | @@ -1940,8 +1946,8 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: u32, flags: u32, fd: fd_t, off |
| 1940 | /// Zig's munmap function does not, for two reasons: | 1946 | /// Zig's munmap function does not, for two reasons: |
| 1941 | /// * It violates the Zig principle that resource deallocation must succeed. | 1947 | /// * It violates the Zig principle that resource deallocation must succeed. |
| 1942 | /// * The Windows function, VirtualFree, has this restriction. | 1948 | /// * The Windows function, VirtualFree, has this restriction. |
| 1943 | pub fn munmap(address: usize, length: usize) void { | 1949 | pub fn munmap(memory: []align(mem.page_size) u8) void { |
| 1944 | switch (errno(system.munmap(address, length))) { | 1950 | switch (errno(system.munmap(memory.ptr, memory.len))) { |
| 1945 | 0 => return, | 1951 | 0 => return, |
| 1946 | EINVAL => unreachable, // Invalid parameters. | 1952 | EINVAL => unreachable, // Invalid parameters. |
| 1947 | ENOMEM => unreachable, // Attempted to unmap a region in the middle of an existing mapping. | 1953 | ENOMEM => unreachable, // Attempted to unmap a region in the middle of an existing mapping. |
std/os/bits/linux.zig+2-1| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("../../std.zig"); | 1 | const std = @import("../../std.zig"); |
| 2 | const maxInt = std.math.maxInt; | ||
| 2 | 3 | ||
| 3 | pub use @import("linux/errno.zig"); | 4 | pub use @import("linux/errno.zig"); |
| 4 | pub use switch (builtin.arch) { | 5 | pub use switch (builtin.arch) { |
| ... | @@ -39,7 +40,7 @@ pub const PROT_EXEC = 4; | ... | @@ -39,7 +40,7 @@ pub const PROT_EXEC = 4; |
| 39 | pub const PROT_GROWSDOWN = 0x01000000; | 40 | pub const PROT_GROWSDOWN = 0x01000000; |
| 40 | pub const PROT_GROWSUP = 0x02000000; | 41 | pub const PROT_GROWSUP = 0x02000000; |
| 41 | 42 | ||
| 42 | pub const MAP_FAILED = maxInt(usize); | 43 | pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); |
| 43 | pub const MAP_SHARED = 0x01; | 44 | pub const MAP_SHARED = 0x01; |
| 44 | pub const MAP_PRIVATE = 0x02; | 45 | pub const MAP_PRIVATE = 0x02; |
| 45 | pub const MAP_TYPE = 0x0f; | 46 | pub const MAP_TYPE = 0x0f; |
std/os/linux.zig+4-4| ... | @@ -173,12 +173,12 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of | ... | @@ -173,12 +173,12 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of |
| 173 | return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); | 173 | return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | pub fn mprotect(address: usize, length: usize, protection: usize) usize { | 176 | pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize { |
| 177 | return syscall3(SYS_mprotect, address, length, protection); | 177 | return syscall3(SYS_mprotect, @ptrToInt(address), length, protection); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | pub fn munmap(address: usize, length: usize) usize { | 180 | pub fn munmap(address: [*]const u8, length: usize) usize { |
| 181 | return syscall2(SYS_munmap, address, length); | 181 | return syscall2(SYS_munmap, @ptrToInt(address), length); |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | pub fn read(fd: i32, buf: [*]u8, count: usize) usize { | 184 | pub fn read(fd: i32, buf: [*]u8, count: usize) usize { |
std/os/linux/tls.zig+2-2| ... | @@ -237,7 +237,7 @@ pub fn allocateTLS(size: usize) usize { | ... | @@ -237,7 +237,7 @@ pub fn allocateTLS(size: usize) usize { |
| 237 | return @ptrToInt(&main_thread_tls_buffer); | 237 | return @ptrToInt(&main_thread_tls_buffer); |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | const addr = os.mmap( | 240 | const slice = os.mmap( |
| 241 | null, | 241 | null, |
| 242 | size, | 242 | size, |
| 243 | os.PROT_READ | os.PROT_WRITE, | 243 | os.PROT_READ | os.PROT_WRITE, |
| ... | @@ -246,5 +246,5 @@ pub fn allocateTLS(size: usize) usize { | ... | @@ -246,5 +246,5 @@ pub fn allocateTLS(size: usize) usize { |
| 246 | 0, | 246 | 0, |
| 247 | ) catch @panic("out of memory"); | 247 | ) catch @panic("out of memory"); |
| 248 | 248 | ||
| 249 | return addr; | 249 | return @ptrToInt(slice.ptr); |
| 250 | } | 250 | } |
test/stage1/behavior/cast.zig+1-1| ... | @@ -318,7 +318,7 @@ fn testCastPtrOfArrayToSliceAndPtr() void { | ... | @@ -318,7 +318,7 @@ fn testCastPtrOfArrayToSliceAndPtr() void { |
| 318 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { | 318 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { |
| 319 | const window_name = [1][*]const u8{c"window name"}; | 319 | const window_name = [1][*]const u8{c"window name"}; |
| 320 | const x: [*]const ?[*]const u8 = &window_name; | 320 | const x: [*]const ?[*]const u8 = &window_name; |
| 321 | expect(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); | 321 | expect(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name")); |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | test "@intCast comptime_int" { | 324 | test "@intCast comptime_int" { |
test/stage1/behavior/misc.zig+2-3| ... | @@ -2,7 +2,6 @@ const std = @import("std"); | ... | @@ -2,7 +2,6 @@ const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | 3 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const cstr = std.cstr; | ||
| 6 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 7 | const maxInt = std.math.maxInt; | 6 | const maxInt = std.math.maxInt; |
| 8 | 7 | ||
| ... | @@ -210,7 +209,7 @@ test "multiline C string" { | ... | @@ -210,7 +209,7 @@ test "multiline C string" { |
| 210 | c\\three | 209 | c\\three |
| 211 | ; | 210 | ; |
| 212 | const s2 = c"one\ntwo)\nthree"; | 211 | const s2 = c"one\ntwo)\nthree"; |
| 213 | expect(cstr.cmp(s1, s2) == 0); | 212 | expect(std.cstr.cmp(s1, s2) == 0); |
| 214 | } | 213 | } |
| 215 | 214 | ||
| 216 | test "type equality" { | 215 | test "type equality" { |
| ... | @@ -363,7 +362,7 @@ test "C string concatenation" { | ... | @@ -363,7 +362,7 @@ test "C string concatenation" { |
| 363 | const a = c"OK" ++ c" IT " ++ c"WORKED"; | 362 | const a = c"OK" ++ c" IT " ++ c"WORKED"; |
| 364 | const b = c"OK IT WORKED"; | 363 | const b = c"OK IT WORKED"; |
| 365 | 364 | ||
| 366 | const len = cstr.len(b); | 365 | const len = mem.len(u8, b); |
| 367 | const len_with_null = len + 1; | 366 | const len_with_null = len + 1; |
| 368 | { | 367 | { |
| 369 | var i: u32 = 0; | 368 | var i: u32 = 0; |