Coercing a slice to an array

How would you coerce a slice to an array?

I would like to pass a (small) portion of a buffer to a function, as an array. So, I thought, why not slice it, and then coerce that slice to array, since I know the length.

The only way I have found is quite awkward:

const std = @import("std");
const native_endian = @import("builtin").target.cpu.arch.endian();

pub fn main() void
{
    var buf = [_]u8 { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE };
    const sl = buf[0..4];
    const u = bytesToU32(@as([4]u8, @as(*[4]u8, @ptrCast(sl.ptr)).*));
    std.debug.print("u = 0x{x}\n", .{ u });
}

fn bytesToU32(b: [4]u8) u32
{
    if (native_endian == .big)
        return b[0] | (@as(u32, b[1]) << 8) | (@as(u32, b[2]) << 16) | (@as(u32, b[3]) << 24)
    else
        return (@as(u32, b[0]) << 24) | (@as(u32, b[1]) << 16) | (@as(u32, b[2]) << 8) | b[3];
}

This works, but @as([4]u8, @as(*[4]u8, @ptrCast(sl.ptr)).*) is really quite ugly.
There just has to be a better way.

sl is already * [4]u8

1 Like

Oh.
This reduces the coercion to @as([4]u8, sl.*) then.

Wait, I can just use sl.*. Brilliant!

Thank you!

3 Likes

However, sl.* only works if sl’s indices ([0..4]) are comptime-known, right?
Doesn’t work if I do something like

    var pos: u32 = 0;
    pos = 2;
    const sl = buf[(pos+0)..(pos+4)];
error: index syntax required for slice type '[]u8'
    const u = bytesToU32(sl.*);
                         ~~^~

The original ugly version does work though.

What about buf[pos..][0..4]? The first subscript is a slice, but the second is a ponter to an array, because the lenth is comptime known.

3 Likes

The size must be comptime known, but the offset doesn’t need to be:

 const sl = buf[pos..][0..4];

This will also produce a * [4]u8.

2 Likes

Thank you.

Took me some time to figure out what it means, as [ ][ ] notation looks like indexing a 2-dimensional array to my eyes.

I think I’m going to write it like (buf[pos..])[0..4], just for clarity.

2 Likes