Copying [*c]u8 to []const u8

Hey everyone!

I have a project where I need to interface with GNU’s readline repo. I managed to copy out a [*c]u8 to a []const u8 with the following:

const c_imports = @cImport({
    @cInclude("stdio.h");
    @cInclude("readline/readline.h");
    @cInclude("readline/history.h");
});
//...
const raw_input = c_imports.readline(">> ") orelse return error.NullRawInput;
// Skipping over null checks, etc. for brevity
const c_len = c_imports.strlen(raw_input);
var zig_array = try std.ArrayListUnmanaged(u8).initCapacity(loop_alloc, @intCast(c_len));
for (0..c_len) |i| {
    zig_array.appendAssumeCapacity(raw_input[i]);
}
// Access bytes by using zig_array.items

This solution works just fine for my use-case, but it feels… verbose? unidiomatic? just plain off?

What are “better” ways to copy from [*c]u8 to []const u8?

You can use

const zig_slice_copy = loop_alloc.dupe(u8, raw_input[0..c_len]);

Also if you want to stay in Zig territory, you can use std.mem.span to avoid using strlen from C:

const zig_slice = std.mem.span(raw_input);
const zig_slice_copy = loop_alloc.dupe(u8, zig_slice);
2 Likes

Ahh! std.mem.span was the trick I was looking for. It has a great knock-on effect for my use case, too. What I needed all along was a []const u8, so no more need for allocating. Good find!

1 Like

Just so you know:
If you have the len you can always convert a many-item pointer to a slice by doing ptr[0..len]

1 Like