aboutsummaryrefslogtreecommitdiff
path: root/shared/fs/afs/io/block.zig
blob: 8abd71cb5999b153bb66c4eb85a7fb9874401561 (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
//! AFS Block I/O Interface

pub const BlockError = error{
    ReadFailed,
    WriteFailed,
    OutOfBounds,
    InvalidCell,
    DeviceError,
    NotSupported,
};

/// Block reader interface - implemented by each consumer
pub const BlockReader = struct {
    context: *anyopaque,
    read_fn: *const fn (context: *anyopaque, cell: u64, buffer: []u8) BlockError!void,
    cell_size: u32,
    total_cells: u64,

    pub fn read_cell(self: *const BlockReader, cell: u64, buffer: []u8) BlockError!void {
        if (cell >= self.total_cells) {
            return BlockError.OutOfBounds;
        }
        if (buffer.len < self.cell_size) {
            return BlockError.InvalidCell;
        }
        return self.read_fn(self.context, cell, buffer);
    }

    pub fn read_cells(self: *const BlockReader, start_cell: u64, buffer: []u8) BlockError!void {
        const cells_to_read = buffer.len / self.cell_size;
        var offset: usize = 0;
        var cell = start_cell;

        while (offset < buffer.len and cell < start_cell + cells_to_read) : ({
            offset += self.cell_size;
            cell += 1;
        }) {
            try self.read_cell(cell, buffer[offset..][0..self.cell_size]);
        }
    }
};

/// Block writer interface - implemented by each consumer
pub const BlockWriter = struct {
    context: *anyopaque,
    write_fn: *const fn (context: *anyopaque, cell: u64, data: []const u8) BlockError!void,
    cell_size: u32,
    total_cells: u64,

    pub fn write_cell(self: *const BlockWriter, cell: u64, data: []const u8) BlockError!void {
        if (cell >= self.total_cells) {
            return BlockError.OutOfBounds;
        }
        if (data.len < self.cell_size) {
            return BlockError.InvalidCell;
        }
        return self.write_fn(self.context, cell, data);
    }

    pub fn write_cells(self: *const BlockWriter, start_cell: u64, data: []const u8) BlockError!void {
        const cells_to_write = data.len / self.cell_size;
        var offset: usize = 0;
        var cell = start_cell;

        while (offset < data.len and cell < start_cell + cells_to_write) : ({
            offset += self.cell_size;
            cell += 1;
        }) {
            try self.write_cell(cell, data[offset..][0..self.cell_size]);
        }
    }
};

/// Combined reader/writer for read-write operations
pub const BlockDevice = struct {
    reader: BlockReader,
    writer: BlockWriter,

    pub fn read_cell(self: *const BlockDevice, cell: u64, buffer: []u8) BlockError!void {
        return self.reader.read_cell(cell, buffer);
    }

    pub fn write_cell(self: *const BlockDevice, cell: u64, data: []const u8) BlockError!void {
        return self.writer.write_cell(cell, data);
    }
};