Hey all, a very inexperienced Zig programmer and once a somewhat competent programmer here. I’m trying to make make an API call to MusicBrainz using std.http.Client.fetch()
and parsing the json with std.json.parseFromSlice()
. I got it to a point that I felt was a good prototype, and made a test for it. However, when running this test, I invariably run into this error happening in bytesAsSlice()
:
swebb@mathgta74lcfy3:~/Source/muzigbrainz> /home/swebb/.zvm/master/zig test -freference-trace=14 --test-filter iamthemorning /home/swebb/Source/muzigbrainz/src/root.zig
/home/swebb/.zvm/master/lib/std/mem.zig:4219:70: error: division by zero here causes undefined behavior
return @as(cast_target, @ptrCast(bytes))[0..@divExact(bytes.len, @sizeOf(T))];
^~~~~~~~~~
referenced by:
remap__anon_372074: /home/swebb/.zvm/master/lib/std/mem/Allocator.zig:335:28
toOwnedSlice: /home/swebb/.zvm/master/lib/std/array_list.zig:114:32
innerParse__anon_368926: /home/swebb/.zvm/master/lib/std/json/static.zig:483:62
innerParse__anon_366535: /home/swebb/.zvm/master/lib/std/json/static.zig:254:42
innerParse__anon_368905: /home/swebb/.zvm/master/lib/std/json/static.zig:363:55
innerParse__anon_366481: /home/swebb/.zvm/master/lib/std/json/static.zig:254:42
innerParse__anon_341775: /home/swebb/.zvm/master/lib/std/json/static.zig:363:55
innerParse__anon_28837: /home/swebb/.zvm/master/lib/std/json/static.zig:476:78
innerParse__anon_22342: /home/swebb/.zvm/master/lib/std/json/static.zig:254:42
innerParse__anon_13432: /home/swebb/.zvm/master/lib/std/json/static.zig:363:55
parseFromTokenSourceLeaky__anon_10129: /home/swebb/.zvm/master/lib/std/json/static.zig:149:33
parseFromTokenSource__anon_7280: /home/swebb/.zvm/master/lib/std/json/static.zig:116:49
parseFromSlice__anon_3431: /home/swebb/.zvm/master/lib/std/json/static.zig:82:32
mbSearch: src/root.zig:42:47
1 reference(s) hidden; use '-freference-trace=15' to see all references
Here is the relevant code being called. I have made a variety of structs in other files to help parse the json (perhaps a remnant of my OOP education), and I can provide those as necessary, I just didn’t want to clutter an already long post, and I’m getting the impression it has more to do with memory management from the code I was trying to decipher:
const Client = std.http.Client;
pub const user_agent: []const u8 = "ZuletztMBClient/0.0.1 (my_email)";
pub fn mbSearch(allocator: std.mem.Allocator, track_name: []const u8, album_name: []const u8, artist_name: []const u8) !?QR.Result {
var client = Client{ .allocator = allocator };
defer client.deinit();
const query: []const u8 = try std.fmt.allocPrint(allocator, "https://musicbrainz.org/ws/2/recording/?query=\"{s}\"%20AND%20artist:\"{s}\"%20AND%20release:\"{s}\"&fmt=json", .{ track_name, artist_name, album_name });
defer allocator.free(query);
var mb_result = std.ArrayList(u8).init(allocator);
errdefer mb_result.deinit();
const response: Client.FetchResult = try client.fetch(.{
.response_storage = .{.dynamic = &mb_result },
.location = .{ .url = query },
.method = .GET,
.headers = .{ .user_agent = .{ .override = user_agent } }
});
switch (@intFromEnum(response.status)) {
0...299 => std.log.debug("Success", .{}),
300...399 => {
std.log.debug("Redirected", .{});
return null;
},
400...511 => return Client.RequestError.ConnectionRefused,
512 => {
std.log.debug("Need to login", .{});
return null;
},
else => unreachable,
}
const mb_result_slice = mb_result.items;
std.log.debug("{s}", .{mb_result_slice});
const result = try std.json.parseFromSlice(QR.Result, allocator, mb_result_slice, .{});
defer result.deinit();
const query_result = result.value;
return query_result;
}
// This test is very volatile, but I think
// these params are specific enough that
// it shouldn't need changing too often
test "iamthemorning" {
const test_alloc = std.testing.allocator;
const track: []const u8 = "Veni Veni Emmanuel";
const album: []const u8 = "Counting the Ghosts";
const artist: []const u8 = "Iamthemorning";
const search_result: ?QR.Result = try mbSearch(test_alloc, track, album, artist);
if (search_result) |sr| {
const result: Entities.Recording = sr.recordings.?[0];
try testing.expect(std.mem.eql(u8, result.id, "5854a6de-af8f-4b99-8710-cb47d6436a19"));
}
}