Skip to content

Commit 431d76c

Browse files
committed
add std.io.StreamSource and fixes to emitRaw
1 parent c71991c commit 431d76c

File tree

5 files changed

+127
-34
lines changed

5 files changed

+127
-34
lines changed

lib/std/build/emit_raw.zig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ const BinaryElfOutput = struct {
4848
};
4949
const elf_hdrs = try std.elf.readAllHeaders(allocator, elf_file);
5050

51-
var binaryElfOutput = BinaryElfOutput.init(arena_allocator);
52-
5351
for (elf_hdrs.section_headers) |section, i| {
5452
if (sectionValidForOutput(section)) {
5553
const newSection = try allocator.create(BinaryElfSection);
@@ -164,7 +162,7 @@ fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !v
164162
var out_file = try fs.cwd().createFile(raw_path, .{});
165163
defer out_file.close();
166164

167-
const binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
165+
var binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
168166
defer binary_elf_output.deinit();
169167

170168
for (binary_elf_output.sections.toSlice()) |section| {

lib/std/elf.zig

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
const builtin = @import("builtin");
21
const std = @import("std.zig");
2+
const builtin = std.builtin;
33
const io = std.io;
44
const os = std.os;
55
const math = std.math;
@@ -352,7 +352,7 @@ pub fn readHeader(file: File) !Header {
352352
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
353353
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
354354

355-
const endian = switch (hdr32.e_ident[EI_DATA]) {
355+
const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
356356
ELFDATA2LSB => .Little,
357357
ELFDATA2MSB => .Big,
358358
else => return error.InvalidElfEndian,
@@ -406,8 +406,8 @@ pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
406406
// Treat section headers and program headers as byte buffers. For 32-bit ELF and
407407
// non-matching endian files, we post-process to correct integer endianness and offsets.
408408

409-
const shdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
410-
const phdr_buf = std.mem.sliceToBytes(hdrs.program_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
409+
const shdr_buf = std.mem.sliceAsBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
410+
const phdr_buf = std.mem.sliceAsBytes(hdrs.program_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
411411

412412
try preadNoEof(file, shdr_buf, hdrs.header.shoff);
413413
try preadNoEof(file, phdr_buf, hdrs.header.phoff);
@@ -430,14 +430,14 @@ pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
430430
}
431431
for (hdrs.program_headers) |*phdr, i| {
432432
phdr.* = .{
433-
.p_type = int(is_64, need_bswap, phdrs32[i].p_type, shdr.p_type),
434-
.p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, shdr.p_offset),
435-
.p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, shdr.p_vaddr),
436-
.p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, shdr.p_paddr),
437-
.p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, shdr.p_filesz),
438-
.p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, shdr.p_memsz),
439-
.p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, shdr.p_flags),
440-
.p_align = int(is_64, need_bswap, phdrs32[i].p_align, shdr.p_align),
433+
.p_type = int(is_64, need_bswap, phdrs32[i].p_type, phdr.p_type),
434+
.p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, phdr.p_offset),
435+
.p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, phdr.p_vaddr),
436+
.p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, phdr.p_paddr),
437+
.p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, phdr.p_filesz),
438+
.p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, phdr.p_memsz),
439+
.p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, phdr.p_flags),
440+
.p_align = int(is_64, need_bswap, phdrs32[i].p_align, phdr.p_align),
441441
};
442442
}
443443
return hdrs;

lib/std/io.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ pub const deserializer = @import("io/serialization.zig").deserializer;
126126

127127
pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile;
128128

129+
pub const StreamSource = @import("io/stream_source.zig").StreamSource;
130+
129131
/// Deprecated; use `std.fs.Dir.writeFile`.
130132
pub fn writeFile(path: []const u8, data: []const u8) !void {
131133
return fs.cwd().writeFile(path, data);

lib/std/io/fixed_buffer_stream.zig

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
1212
buffer: Buffer,
1313
pos: usize,
1414

15-
pub const ReadError = error{EndOfStream};
16-
pub const WriteError = error{OutOfMemory};
17-
pub const SeekError = error{EndOfStream};
15+
pub const ReadError = error{};
16+
pub const WriteError = error{NoSpaceLeft};
17+
pub const SeekError = error{};
1818
pub const GetSeekPosError = error{};
1919

2020
pub const InStream = io.InStream(*Self, ReadError, read);
@@ -51,16 +51,16 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
5151
mem.copy(u8, dest[0..size], self.buffer[self.pos..end]);
5252
self.pos = end;
5353

54-
if (size == 0) return error.EndOfStream;
5554
return size;
5655
}
5756

5857
/// If the returned number of bytes written is less than requested, the
59-
/// buffer is full. Returns `error.OutOfMemory` when no bytes would be written.
58+
/// buffer is full. Returns `error.NoSpaceLeft` when no bytes would be written.
59+
/// Note: `error.NoSpaceLeft` matches the corresponding error from
60+
/// `std.fs.File.WriteError`.
6061
pub fn write(self: *Self, bytes: []const u8) WriteError!usize {
6162
if (bytes.len == 0) return 0;
62-
63-
assert(self.pos <= self.buffer.len);
63+
if (self.pos >= self.buffer.len) return error.NoSpaceLeft;
6464

6565
const n = if (self.pos + bytes.len <= self.buffer.len)
6666
bytes.len
@@ -70,26 +70,27 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
7070
mem.copy(u8, self.buffer[self.pos .. self.pos + n], bytes[0..n]);
7171
self.pos += n;
7272

73-
if (n == 0) return error.OutOfMemory;
73+
if (n == 0) return error.NoSpaceLeft;
7474

7575
return n;
7676
}
7777

7878
pub fn seekTo(self: *Self, pos: u64) SeekError!void {
79-
const usize_pos = std.math.cast(usize, pos) catch return error.EndOfStream;
80-
if (usize_pos > self.buffer.len) return error.EndOfStream;
79+
const usize_pos = std.math.cast(usize, pos) catch std.math.maxInt(usize);
8180
self.pos = usize_pos;
8281
}
8382

8483
pub fn seekBy(self: *Self, amt: i64) SeekError!void {
8584
if (amt < 0) {
86-
const abs_amt = std.math.cast(usize, -amt) catch return error.EndOfStream;
87-
if (abs_amt > self.pos) return error.EndOfStream;
88-
self.pos -= abs_amt;
85+
const abs_amt = std.math.cast(usize, -amt) catch std.math.maxInt(usize);
86+
if (abs_amt > self.pos) {
87+
self.pos = 0;
88+
} else {
89+
self.pos -= abs_amt;
90+
}
8991
} else {
90-
const usize_amt = std.math.cast(usize, amt) catch return error.EndOfStream;
91-
if (self.pos + usize_amt > self.buffer.len) return error.EndOfStream;
92-
self.pos += usize_amt;
92+
const usize_amt = std.math.cast(usize, amt) catch std.math.maxInt(usize);
93+
self.pos = std.math.add(usize, self.pos, usize_amt) catch std.math.maxInt(usize);
9394
}
9495
}
9596

@@ -101,6 +102,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
101102
return self.pos;
102103
}
103104

105+
/// Asserts that the seek pos is within the buffer range.
104106
pub fn getWritten(self: Self) []const u8 {
105107
return self.buffer[0..self.pos];
106108
}
@@ -140,13 +142,13 @@ test "FixedBufferStream output 2" {
140142
try fbs.outStream().writeAll("world");
141143
testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
142144

143-
testing.expectError(error.OutOfMemory, fbs.outStream().writeAll("!"));
145+
testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("!"));
144146
testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
145147

146148
fbs.reset();
147149
testing.expect(fbs.getWritten().len == 0);
148150

149-
testing.expectError(error.OutOfMemory, fbs.outStream().writeAll("Hello world!"));
151+
testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("Hello world!"));
150152
testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl"));
151153
}
152154

@@ -164,5 +166,6 @@ test "FixedBufferStream input" {
164166
testing.expect(read == 3);
165167
testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));
166168

167-
testing.expectError(error.EndOfStream, fbs.inStream().read(dest[0..4]));
169+
read = try fbs.inStream().read(dest[0..4]);
170+
testing.expect(read == 0);
168171
}

lib/std/io/stream_source.zig

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
const std = @import("../std.zig");
2+
const io = std.io;
3+
const testing = std.testing;
4+
5+
/// Provides `io.InStream`, `io.OutStream`, and `io.SeekableStream` for in-memory buffers as
6+
/// well as files.
7+
/// For memory sources, if the supplied byte buffer is const, then `io.OutStream` is not available.
8+
/// The error set of the stream functions is the error set of the corresponding file functions.
9+
pub const StreamSource = union(enum) {
10+
buffer: io.FixedBufferStream([]u8),
11+
const_buffer: io.FixedBufferStream([]const u8),
12+
file: std.fs.File,
13+
14+
pub const ReadError = std.fs.File.ReadError;
15+
pub const WriteError = std.fs.File.WriteError;
16+
pub const SeekError = std.fs.File.SeekError;
17+
pub const GetSeekPosError = std.fs.File.GetPosError;
18+
19+
pub const InStream = io.InStream(*StreamSource, ReadError, read);
20+
pub const OutStream = io.OutStream(*StreamSource, WriteError, write);
21+
pub const SeekableStream = io.SeekableStream(
22+
*StreamSource,
23+
SeekError,
24+
GetSeekPosError,
25+
seekTo,
26+
seekBy,
27+
getPos,
28+
getEndPos,
29+
);
30+
31+
pub fn read(self: *StreamSource, dest: []u8) ReadError!usize {
32+
switch (self.*) {
33+
.buffer => |*x| return x.read(dest),
34+
.const_buffer => |*x| return x.read(dest),
35+
.file => |x| return x.read(dest),
36+
}
37+
}
38+
39+
pub fn write(self: *StreamSource, bytes: []const u8) WriteError!usize {
40+
switch (self.*) {
41+
.buffer => |*x| return x.write(bytes),
42+
.const_buffer => |*x| return x.write(bytes),
43+
.file => |x| return x.write(bytes),
44+
}
45+
}
46+
47+
pub fn seekTo(self: *StreamSource, pos: u64) SeekError!void {
48+
switch (self.*) {
49+
.buffer => |*x| return x.seekTo(pos),
50+
.const_buffer => |*x| return x.seekTo(pos),
51+
.file => |x| return x.seekTo(pos),
52+
}
53+
}
54+
55+
pub fn seekBy(self: *StreamSource, amt: i64) SeekError!void {
56+
switch (self.*) {
57+
.buffer => |*x| return x.seekBy(amt),
58+
.const_buffer => |*x| return x.seekBy(amt),
59+
.file => |x| return x.seekBy(amt),
60+
}
61+
}
62+
63+
pub fn getEndPos(self: *StreamSource) GetSeekPosError!u64 {
64+
switch (self.*) {
65+
.buffer => |*x| return x.getEndPos(),
66+
.const_buffer => |*x| return x.getEndPos(),
67+
.file => |x| return x.getEndPos(),
68+
}
69+
}
70+
71+
pub fn getPos(self: *StreamSource) GetSeekPosError!u64 {
72+
switch (self.*) {
73+
.buffer => |*x| return x.getPos(),
74+
.const_buffer => |*x| return x.getPos(),
75+
.file => |x| return x.getPos(),
76+
}
77+
}
78+
79+
pub fn inStream(self: *StreamSource) InStream {
80+
return .{ .context = self };
81+
}
82+
83+
pub fn outStream(self: *StreamSource) OutStream {
84+
return .{ .context = self };
85+
}
86+
87+
pub fn seekableStream(self: *StreamSource) SeekableStream {
88+
return .{ .context = self };
89+
}
90+
};

0 commit comments

Comments
 (0)