move tax type to enum

This commit is contained in:
Emil Lerch 2026-03-06 13:51:19 -08:00
parent 57b0811ecd
commit f1e9321bdc
Signed by: lobo
GPG key ID: A7B62D657EF764F8

View file

@ -17,10 +17,27 @@ pub const BreakdownItem = struct {
weight: f64, // fraction of total (0.0 - 1.0) weight: f64, // fraction of total (0.0 - 1.0)
}; };
/// Tax type classification for accounts.
pub const TaxType = enum {
taxable,
roth,
traditional,
hsa,
pub fn label(self: TaxType) []const u8 {
return switch (self) {
.taxable => "Taxable",
.roth => "Roth (Post-Tax)",
.traditional => "Traditional (Pre-Tax)",
.hsa => "HSA (Triple Tax-Free)",
};
}
};
/// Account tax type classification entry, parsed from accounts.srf. /// Account tax type classification entry, parsed from accounts.srf.
pub const AccountTaxEntry = struct { pub const AccountTaxEntry = struct {
account: []const u8, account: []const u8,
tax_type: []const u8, tax_type: TaxType,
}; };
/// Parsed account metadata. /// Parsed account metadata.
@ -31,7 +48,6 @@ pub const AccountMap = struct {
pub fn deinit(self: *AccountMap) void { pub fn deinit(self: *AccountMap) void {
for (self.entries) |e| { for (self.entries) |e| {
self.allocator.free(e.account); self.allocator.free(e.account);
self.allocator.free(e.tax_type);
} }
self.allocator.free(self.entries); self.allocator.free(self.entries);
} }
@ -40,22 +56,13 @@ pub const AccountMap = struct {
pub fn taxTypeFor(self: AccountMap, account: []const u8) []const u8 { pub fn taxTypeFor(self: AccountMap, account: []const u8) []const u8 {
for (self.entries) |e| { for (self.entries) |e| {
if (std.mem.eql(u8, e.account, account)) { if (std.mem.eql(u8, e.account, account)) {
return taxTypeLabel(e.tax_type); return e.tax_type.label();
} }
} }
return "Unknown"; return "Unknown";
} }
}; };
/// Map raw tax_type strings to display labels.
fn taxTypeLabel(raw: []const u8) []const u8 {
if (std.mem.eql(u8, raw, "taxable")) return "Taxable";
if (std.mem.eql(u8, raw, "roth")) return "Roth (Post-Tax)";
if (std.mem.eql(u8, raw, "traditional")) return "Traditional (Pre-Tax)";
if (std.mem.eql(u8, raw, "hsa")) return "HSA (Triple Tax-Free)";
return raw;
}
/// Parse an accounts.srf file into an AccountMap. /// Parse an accounts.srf file into an AccountMap.
/// Each record has: account::<NAME>,tax_type::<TYPE> /// Each record has: account::<NAME>,tax_type::<TYPE>
pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !AccountMap { pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !AccountMap {
@ -63,7 +70,6 @@ pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !Accoun
errdefer { errdefer {
for (entries.items) |e| { for (entries.items) |e| {
allocator.free(e.account); allocator.free(e.account);
allocator.free(e.tax_type);
} }
entries.deinit(allocator); entries.deinit(allocator);
} }
@ -76,7 +82,7 @@ pub fn parseAccountsFile(allocator: std.mem.Allocator, data: []const u8) !Accoun
const entry = record.to(AccountTaxEntry) catch continue; const entry = record.to(AccountTaxEntry) catch continue;
try entries.append(allocator, .{ try entries.append(allocator, .{
.account = try allocator.dupe(u8, entry.account), .account = try allocator.dupe(u8, entry.account),
.tax_type = try allocator.dupe(u8, entry.tax_type), .tax_type = entry.tax_type,
}); });
} }
@ -287,13 +293,11 @@ test "parseAccountsFile" {
try std.testing.expectEqualStrings("Unknown", am.taxTypeFor("Nonexistent")); try std.testing.expectEqualStrings("Unknown", am.taxTypeFor("Nonexistent"));
} }
test "taxTypeLabel" { test "TaxType.label" {
try std.testing.expectEqualStrings("Taxable", taxTypeLabel("taxable")); try std.testing.expectEqualStrings("Taxable", TaxType.taxable.label());
try std.testing.expectEqualStrings("Roth (Post-Tax)", taxTypeLabel("roth")); try std.testing.expectEqualStrings("Roth (Post-Tax)", TaxType.roth.label());
try std.testing.expectEqualStrings("Traditional (Pre-Tax)", taxTypeLabel("traditional")); try std.testing.expectEqualStrings("Traditional (Pre-Tax)", TaxType.traditional.label());
try std.testing.expectEqualStrings("HSA (Triple Tax-Free)", taxTypeLabel("hsa")); try std.testing.expectEqualStrings("HSA (Triple Tax-Free)", TaxType.hsa.label());
// Unknown type returns raw string
try std.testing.expectEqualStrings("custom_type", taxTypeLabel("custom_type"));
} }
test "mapToSortedBreakdown" { test "mapToSortedBreakdown" {