introduce deinit on Dividend

This commit is contained in:
Emil Lerch 2026-03-06 14:59:14 -08:00
parent bbdf340de4
commit 3d679f9d75
Signed by: lobo
GPG key ID: A7B62D657EF764F8
6 changed files with 42 additions and 12 deletions

9
src/cache/store.zig vendored
View file

@ -268,10 +268,13 @@ pub const Store = struct {
/// Deserialize dividends from SRF data.
pub fn deserializeDividends(allocator: std.mem.Allocator, data: []const u8) ![]Dividend {
var dividends: std.ArrayList(Dividend) = .empty;
errdefer dividends.deinit(allocator);
errdefer {
for (dividends.items) |d| d.deinit(allocator);
dividends.deinit(allocator);
}
var reader = std.Io.Reader.fixed(data);
const parsed = srf.parse(&reader, allocator, .{ .alloc_strings = false }) catch return error.InvalidData;
const parsed = srf.parse(&reader, allocator, .{ .alloc_strings = true }) catch return error.InvalidData;
defer parsed.deinit();
for (parsed.records.items) |record| {
@ -794,7 +797,7 @@ test "dividend serialize/deserialize round-trip" {
defer allocator.free(data);
const parsed = try Store.deserializeDividends(allocator, data);
defer allocator.free(parsed);
defer Dividend.freeSlice(allocator, parsed);
try std.testing.expectEqual(@as(usize, 2), parsed.len);

View file

@ -14,7 +14,7 @@ pub fn run(allocator: std.mem.Allocator, svc: *zfin.DataService, symbol: []const
return;
},
};
defer allocator.free(result.data);
defer zfin.Dividend.freeSlice(allocator, result.data);
if (result.source == .cached) try cli.stderrPrint("(using cached dividend data)\n");

View file

@ -15,7 +15,7 @@ pub fn run(allocator: std.mem.Allocator, svc: *zfin.DataService, symbol: []const
},
};
defer allocator.free(result.candles);
defer if (result.dividends) |d| allocator.free(d);
defer if (result.dividends) |d| zfin.Dividend.freeSlice(allocator, d);
if (result.source == .cached) try cli.stderrPrint("(using cached data)\n");

View file

@ -1,3 +1,4 @@
const std = @import("std");
const Date = @import("date.zig").Date;
pub const DividendType = enum {
@ -22,6 +23,17 @@ pub const Dividend = struct {
frequency: ?u8 = null,
/// Classification of the dividend
type: DividendType = .unknown,
/// Currency code (e.g., "USD")
/// Currency code (e.g., "USD"). Heap-allocated; freed by deinit().
currency: ?[]const u8 = null,
/// Free any owned string fields.
pub fn deinit(self: Dividend, allocator: std.mem.Allocator) void {
if (self.currency) |c| allocator.free(c);
}
/// Free a slice of dividends, calling deinit on each element first.
pub fn freeSlice(allocator: std.mem.Allocator, divs: []const Dividend) void {
for (divs) |d| d.deinit(allocator);
allocator.free(divs);
}
};

View file

@ -50,7 +50,10 @@ pub const Polygon = struct {
to: ?Date,
) provider.ProviderError![]Dividend {
var all_dividends: std.ArrayList(Dividend) = .empty;
errdefer all_dividends.deinit(allocator);
errdefer {
for (all_dividends.items) |d| d.deinit(allocator);
all_dividends.deinit(allocator);
}
var next_url: ?[]const u8 = null;
defer if (next_url) |u| allocator.free(u);
@ -248,7 +251,10 @@ fn parseDividendsPage(
.record_date = parseDateField(obj, "record_date"),
.frequency = parseFrequency(obj),
.type = parseDividendType(obj),
.currency = jsonStr(obj.get("currency")),
.currency = if (jsonStr(obj.get("currency"))) |s|
(allocator.dupe(u8, s) catch null)
else
null,
}) catch return provider.ProviderError.OutOfMemory;
}
@ -442,7 +448,10 @@ test "parseDividendsPage basic" {
const allocator = std.testing.allocator;
var out = std.ArrayList(Dividend).empty;
defer out.deinit(allocator);
defer {
for (out.items) |d| d.deinit(allocator);
out.deinit(allocator);
}
const next_url = try parseDividendsPage(allocator, body, &out);
try std.testing.expect(next_url == null);
@ -471,7 +480,10 @@ test "parseDividendsPage with pagination" {
const allocator = std.testing.allocator;
var out = std.ArrayList(Dividend).empty;
defer out.deinit(allocator);
defer {
for (out.items) |d| d.deinit(allocator);
out.deinit(allocator);
}
const next_url = try parseDividendsPage(allocator, body, &out);
try std.testing.expect(next_url != null);
@ -488,7 +500,10 @@ test "parseDividendsPage error status" {
const allocator = std.testing.allocator;
var out = std.ArrayList(Dividend).empty;
defer out.deinit(allocator);
defer {
for (out.items) |d| d.deinit(allocator);
out.deinit(allocator);
}
const result = parseDividendsPage(allocator, body, &out);
try std.testing.expectError(provider.ProviderError.RequestFailed, result);

View file

@ -1606,7 +1606,7 @@ const App = struct {
}
fn freeDividends(self: *App) void {
if (self.dividends) |d| self.allocator.free(d);
if (self.dividends) |d| zfin.Dividend.freeSlice(self.allocator, d);
self.dividends = null;
}