Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

evalGeneric

Uses arena to allocate the result.

Run.evalGeneric
fn evalGeneric(
    arena: Allocator,
    run_index: Configuration.Step.Index,
    maker: *Maker,
    spawn_options: process.SpawnOptions,
) !EvalGenericResult

File

Code

fn evalGeneric(
    arena: Allocator,
    run_index: Configuration.Step.Index,
    maker: *Maker,
    spawn_options: process.SpawnOptions,
) !EvalGenericResult {
    const graph = maker.graph;
    const io = graph.io;
    const conf = &maker.scanned_config.configuration;
    const conf_step = run_index.ptr(conf);
    const conf_run = conf_step.extended.get(conf.extra).run;
    const step = maker.stepByIndex(run_index);

    var child = try process.spawn(io, spawn_options);
    defer child.kill(io);

    switch (conf_run.stdin.u) {
        .bytes => |bytes| {
            child.stdin.?.writeStreamingAll(io, bytes.slice(conf)) catch |err| {
                return step.fail(maker, "failed to write stdin: {t}", .{err});
            };
            child.stdin.?.close(io);
            child.stdin = null;
        },
        .lazy_path => |lazy_path| {
            const path = try maker.resolveLazyPathIndex(arena, lazy_path, run_index);
            const file = path.root_dir.handle.openFile(io, path.subPathOrDot(), .{}) catch |err| {
                return step.fail(maker, "failed to open stdin file: {t}", .{err});
            };
            defer file.close(io);
            // TODO https://github.com/ziglang/zig/issues/23955
            var read_buffer: [1024]u8 = undefined;
            var file_reader = file.reader(io, &read_buffer);
            var write_buffer: [1024]u8 = undefined;
            var stdin_writer = child.stdin.?.writerStreaming(io, &write_buffer);
            _ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) {
                error.ReadFailed => return step.fail(maker, "failed to read from {f}: {t}", .{
                    path, file_reader.err.?,
                }),
                error.WriteFailed => return step.fail(maker, "failed to write to stdin: {t}", .{
                    stdin_writer.err.?,
                }),
            };
            stdin_writer.interface.flush() catch |err| switch (err) {
                error.WriteFailed => return step.fail(maker, "failed to write to stdin: {t}", .{
                    stdin_writer.err.?,
                }),
            };
            child.stdin.?.close(io);
            child.stdin = null;
        },
        .none => {},
    }

    var stdout_bytes: ?[]const u8 = null;
    var stderr_bytes: ?[]const u8 = null;

    if (child.stdout) |stdout| {
        if (child.stderr) |stderr| {
            var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined;
            var multi_reader: Io.File.MultiReader = undefined;
            multi_reader.init(arena, io, multi_reader_buffer.toStreams(), &.{ stdout, stderr });

            const stdout_reader = multi_reader.reader(0);
            const stderr_reader = multi_reader.reader(1);

            while (multi_reader.fill(64, .none)) |_| {
                if (conf_run.stdio_limit.value) |limit| {
                    if (stdout_reader.buffered().len > limit)
                        return error.StdoutStreamTooLong;
                    if (stderr_reader.buffered().len > limit)
                        return error.StderrStreamTooLong;
                }
            } else |err| switch (err) {
                error.Timeout => unreachable,
                error.EndOfStream => {},
                else => |e| return e,
            }

            try multi_reader.checkAnyError();

            stdout_bytes = multi_reader.reader(0).buffered();
            stderr_bytes = multi_reader.reader(1).buffered();
        } else {
            var stdout_reader = stdout.readerStreaming(io, &.{});
            const stdio_limit: Io.Limit = if (conf_run.stdio_limit.value) |x| .limited64(x) else .unlimited;
            stdout_bytes = stdout_reader.interface.allocRemaining(arena, stdio_limit) catch |err| switch (err) {
                error.OutOfMemory => |e| return e,
                error.ReadFailed => return stdout_reader.err.?,
                error.StreamTooLong => return error.StdoutStreamTooLong,
            };
        }
    } else if (child.stderr) |stderr| {
        var stderr_reader = stderr.readerStreaming(io, &.{});
        const stdio_limit: Io.Limit = if (conf_run.stdio_limit.value) |x| .limited64(x) else .unlimited;
        stderr_bytes = stderr_reader.interface.allocRemaining(arena, stdio_limit) catch |err| switch (err) {
            error.OutOfMemory => |e| return e,
            error.ReadFailed => return stderr_reader.err.?,
            error.StreamTooLong => return error.StderrStreamTooLong,
        };
    }

    if (stderr_bytes) |bytes| if (bytes.len > 0) {
        // Treat stderr as an error message.
        const stderr_is_diagnostic = conf_run.captured_stderr.value == null and switch (conf_run.flags.stdio) {
            .check => !checksContainStderr(&conf_run),
            else => true,
        };
        if (stderr_is_diagnostic) {
            try step.setResultStderr(maker.gpa, bytes);
        }
    };

    step.result_peak_rss = child.resource_usage_statistics.getMaxRss() orelse 0;

    return .{
        .term = try child.wait(io),
        .stdout = stdout_bytes,
        .stderr = stderr_bytes,
    };
}