talked AI into using a cImport and removed 60 LoC of duplicate code

This commit is contained in:
Emil Lerch 2025-12-18 15:54:17 -08:00
parent 4195f43fa7
commit 2834763c0a
Signed by: lobo
GPG key ID: A7B62D657EF764F8
2 changed files with 35 additions and 94 deletions

View file

@ -61,6 +61,8 @@ pub fn build(b: *std.Build) void {
exe.root_module.addAnonymousImport("airports.dat", .{
.root_source_file = openflights.path("data/airports.dat"),
});
exe.root_module.addIncludePath(maxminddb_upstream.path("include"));
exe.root_module.addConfigHeader(maxminddb_config);
exe.linkLibrary(maxminddb);
exe.linkLibC();
@ -86,6 +88,8 @@ pub fn build(b: *std.Build) void {
tests.root_module.addAnonymousImport("airports.dat", .{
.root_source_file = openflights.path("data/airports.dat"),
});
tests.root_module.addIncludePath(maxminddb_upstream.path("include"));
tests.root_module.addConfigHeader(maxminddb_config);
tests.linkLibrary(maxminddb);
tests.linkLibC();

View file

@ -1,94 +1,29 @@
const std = @import("std");
const Coordinates = @import("../Coordinates.zig");
pub const MMDB = extern struct {
filename: [*:0]const u8,
flags: u32,
file_content: ?*anyopaque,
file_size: usize,
data_section: ?*anyopaque,
data_section_size: u32,
metadata_section: ?*anyopaque,
metadata_section_size: u32,
full_record_byte_size: u16,
depth: u16,
ipv4_start_node: extern struct {
node_value: u32,
netmask: u16,
},
metadata: extern struct {
node_count: u32,
record_size: u16,
ip_version: u16,
database_type: [*:0]const u8,
languages: extern struct {
count: usize,
names: [*][*:0]const u8,
},
binary_format_major_version: u16,
binary_format_minor_version: u16,
build_epoch: u64,
description: extern struct {
count: usize,
descriptions: [*]?*anyopaque,
},
},
};
pub const MMDBLookupResult = extern struct {
found_entry: bool,
entry: MMDBEntry,
netmask: u16,
};
pub const MMDBEntry = extern struct {
mmdb: *MMDB,
offset: u32,
};
pub const MMDBEntryData = extern struct {
has_data: bool,
data_type: u32,
offset: u32,
offset_to_next: u32,
data_size: u32,
utf8_string: [*:0]const u8,
double_value: f64,
bytes: [*]const u8,
uint16: u16,
uint32: u32,
int32: i32,
uint64: u64,
uint128: u128,
boolean: bool,
float_value: f32,
};
extern fn MMDB_open(filename: [*:0]const u8, flags: u32, mmdb: *MMDB) c_int;
extern fn MMDB_close(mmdb: *MMDB) void;
extern fn MMDB_lookup_string(mmdb: *MMDB, ipstr: [*:0]const u8, gai_error: *c_int, mmdb_error: *c_int) MMDBLookupResult;
extern fn MMDB_get_value(entry: *MMDBEntry, entry_data: *MMDBEntryData, ...) c_int;
extern fn MMDB_strerror(error_code: c_int) [*:0]const u8;
const c = @cImport({
@cInclude("maxminddb.h");
});
const GeoIP = @This();
mmdb: MMDB,
mmdb: c.MMDB_s,
pub fn init(db_path: []const u8) !GeoIP {
var mmdb: MMDB = undefined;
const path_z = try std.heap.c_allocator.dupeZ(u8, db_path);
defer std.heap.c_allocator.free(path_z);
const status = MMDB_open(path_z.ptr, 0, &mmdb);
if (status != 0) {
// SAFETY: The C API will initialize this on the next line
var mmdb: c.MMDB_s = undefined;
const status = c.MMDB_open(path_z.ptr, c.MMDB_MODE_MMAP, &mmdb);
if (status != c.MMDB_SUCCESS)
return error.CannotOpenDatabase;
}
return GeoIP{ .mmdb = mmdb };
}
pub fn deinit(self: *GeoIP) void {
MMDB_close(&self.mmdb);
c.MMDB_close(&self.mmdb);
}
pub fn lookup(self: *GeoIP, ip: []const u8) !?Coordinates {
@ -98,7 +33,7 @@ pub fn lookup(self: *GeoIP, ip: []const u8) !?Coordinates {
var gai_error: c_int = 0;
var mmdb_error: c_int = 0;
const result = MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
const result = c.MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
if (gai_error != 0 or mmdb_error != 0) {
return null;
@ -108,7 +43,7 @@ pub fn lookup(self: *GeoIP, ip: []const u8) !?Coordinates {
return null;
}
return try self.extractCoordinates(result.entry);
return try self.extractCoordinates(result);
}
pub fn isUSIP(self: *GeoIP, ip: []const u8) bool {
@ -118,46 +53,48 @@ pub fn isUSIP(self: *GeoIP, ip: []const u8) bool {
var gai_error: c_int = 0;
var mmdb_error: c_int = 0;
const result = MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
const result = c.MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
if (gai_error != 0 or mmdb_error != 0 or !result.found_entry) {
return false;
}
var entry_mut = result.entry;
var country_data: MMDBEntryData = undefined;
const null_term: [*:0]const u8 = @ptrCast(&[_]u8{0});
const status = MMDB_get_value(&entry_mut, &country_data, "country\x00", "iso_code\x00", null_term);
// SAFETY: The C API will initialize this on the next line
var country_data: c.MMDB_entry_data_s = undefined;
const status = c.MMDB_get_value(&entry_mut, &country_data, "country\x00", "iso_code\x00", null_term);
if (status != 0 or !country_data.has_data) {
if (status != c.MMDB_SUCCESS or !country_data.has_data)
return false;
}
const country_code = std.mem.span(country_data.utf8_string);
const country_code = std.mem.span(country_data.unnamed_0.utf8_string);
return std.mem.eql(u8, country_code, "US");
}
fn extractCoordinates(self: *GeoIP, entry: MMDBEntry) !Coordinates {
fn extractCoordinates(self: *GeoIP, result: c.MMDB_lookup_result_s) !Coordinates {
_ = self;
var entry_mut = entry;
var latitude_data: MMDBEntryData = undefined;
var longitude_data: MMDBEntryData = undefined;
var entry_mut = result.entry;
const lat_status = MMDB_get_value(&entry_mut, &latitude_data, "location", "latitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
const lon_status = MMDB_get_value(&entry_mut, &longitude_data, "location", "longitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
// SAFETY: The C API will initialize below
var latitude_data: c.MMDB_entry_data_s = undefined;
// SAFETY: The C API will initialize below
var longitude_data: c.MMDB_entry_data_s = undefined;
if (lat_status != 0 or lon_status != 0 or !latitude_data.has_data or !longitude_data.has_data) {
const lat_status = c.MMDB_get_value(&entry_mut, &latitude_data, "location", "latitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
const lon_status = c.MMDB_get_value(&entry_mut, &longitude_data, "location", "longitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
if (lat_status != c.MMDB_SUCCESS or lon_status != c.MMDB_SUCCESS or !latitude_data.has_data or !longitude_data.has_data)
return error.CoordinatesNotFound;
}
return Coordinates{
.latitude = latitude_data.double_value,
.longitude = longitude_data.double_value,
return .{
.latitude = latitude_data.unnamed_0.double_value,
.longitude = longitude_data.unnamed_0.double_value,
};
}
test "MMDB functions are callable" {
const mmdb_error = MMDB_strerror(0);
const mmdb_error = c.MMDB_strerror(0);
try std.testing.expect(mmdb_error[0] != 0);
}