aboutsummaryrefslogtreecommitdiff
path: root/shared/fs/afs/read/unit.zig
blob: cecd5f728d694a3dbad12e5834bbd54977b39974 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//! AFS Unit Read Operations

const constants = @import("../constants/constants.zig");
const types = @import("../types/types.zig");
const io = @import("../io/io.zig");

const BlockReader = io.BlockReader;
const BlockError = io.BlockError;
const SpanDescriptor = types.SpanDescriptor;
const ChannelInfo = types.ChannelInfo;
const UnitRecord = types.UnitRecord;

pub const ReadError = error{
    ReadFailed,
    UnitTooLarge,
    InvalidSpan,
    BufferTooSmall,
};

/// Read data from a span into a buffer
pub fn read_span(
    reader: *const BlockReader,
    span: *const SpanDescriptor,
    buffer: []u8,
    cell_buffer: []u8,
) ReadError!u64 {
    const span_bytes = span.byte_size(reader.cell_size);
    const bytes_to_read = if (buffer.len < span_bytes) buffer.len else span_bytes;

    var bytes_read: u64 = 0;
    var current_cell = span.start_cell;

    while (bytes_read < bytes_to_read) {
        reader.read_cell(current_cell, cell_buffer) catch {
            return ReadError.ReadFailed;
        };

        const bytes_remaining = bytes_to_read - bytes_read;
        const bytes_to_copy = if (bytes_remaining < reader.cell_size) bytes_remaining else reader.cell_size;

        var i: u64 = 0;
        while (i < bytes_to_copy) : (i += 1) {
            buffer[@intCast(bytes_read + i)] = cell_buffer[@intCast(i)];
        }

        bytes_read += bytes_to_copy;
        current_cell += 1;
    }

    return bytes_read;
}

/// Read unit data using inline spans
pub fn read_unit_inline_spans(
    reader: *const BlockReader,
    channel: *const ChannelInfo,
    buffer: []u8,
    cell_buffer: []u8,
) ReadError!u64 {
    const unit_size = channel.logical_size;

    if (buffer.len < unit_size) {
        return ReadError.BufferTooSmall;
    }

    var bytes_read: u64 = 0;
    var span_index: usize = 0;

    while (bytes_read < unit_size and span_index < constants.span_inline_count) {
        const span = channel.get_span(span_index);
        if (span == null) {
            break;
        }

        const span_bytes = span.?.byte_size(reader.cell_size);
        const bytes_remaining = unit_size - bytes_read;
        const bytes_to_read = if (bytes_remaining < span_bytes) bytes_remaining else span_bytes;

        const dest_slice = buffer[@intCast(bytes_read)..@intCast(bytes_read + bytes_to_read)];
        _ = try read_span(reader, span.?, dest_slice, cell_buffer);

        bytes_read += bytes_to_read;
        span_index += 1;
    }

    return bytes_read;
}

/// Read entire unit data (inline spans only, no overflow support yet)
pub fn read_unit(
    reader: *const BlockReader,
    unit: *const UnitRecord,
    buffer: []u8,
    cell_buffer: []u8,
) ReadError!u64 {
    return read_unit_inline_spans(reader, &unit.data_channel, buffer, cell_buffer);
}