vlean up geocache
This commit is contained in:
parent
e8e31b25e8
commit
7dc4336474
1 changed files with 129 additions and 30 deletions
|
|
@ -88,6 +88,34 @@ pub fn saveIfNeeded(self: *GeoCache) void {
|
||||||
self.last_save = now;
|
self.last_save = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load(allocator: std.mem.Allocator, cache: *std.StringHashMap(CachedLocation), content: []const u8) !void {
|
||||||
|
const CacheData = struct {
|
||||||
|
name: []const u8,
|
||||||
|
latitude: f64,
|
||||||
|
longitude: f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
const parsed = try std.json.parseFromSlice(
|
||||||
|
std.json.ArrayHashMap(CacheData),
|
||||||
|
allocator,
|
||||||
|
content,
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
defer parsed.deinit();
|
||||||
|
|
||||||
|
for (parsed.value.map.keys(), parsed.value.map.values()) |key, value| {
|
||||||
|
const cache_key = try allocator.dupe(u8, key);
|
||||||
|
const cache_value = CachedLocation{
|
||||||
|
.name = try allocator.dupe(u8, value.name),
|
||||||
|
.coords = .{
|
||||||
|
.latitude = value.latitude,
|
||||||
|
.longitude = value.longitude,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try cache.put(cache_key, cache_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn loadFromFile(allocator: std.mem.Allocator, cache: *std.StringHashMap(CachedLocation), file_path: []const u8) !void {
|
fn loadFromFile(allocator: std.mem.Allocator, cache: *std.StringHashMap(CachedLocation), file_path: []const u8) !void {
|
||||||
const file = try std.fs.cwd().openFile(file_path, .{});
|
const file = try std.fs.cwd().openFile(file_path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
@ -95,37 +123,10 @@ fn loadFromFile(allocator: std.mem.Allocator, cache: *std.StringHashMap(CachedLo
|
||||||
const content = try file.readToEndAlloc(allocator, 10 * 1024 * 1024); // 10MB max
|
const content = try file.readToEndAlloc(allocator, 10 * 1024 * 1024); // 10MB max
|
||||||
defer allocator.free(content);
|
defer allocator.free(content);
|
||||||
|
|
||||||
const parsed = try std.json.parseFromSlice(
|
try load(allocator, cache, content);
|
||||||
std.json.Value,
|
|
||||||
allocator,
|
|
||||||
content,
|
|
||||||
.{},
|
|
||||||
);
|
|
||||||
defer parsed.deinit();
|
|
||||||
|
|
||||||
var it = parsed.value.object.iterator();
|
|
||||||
while (it.next()) |entry| {
|
|
||||||
const obj = entry.value_ptr.object;
|
|
||||||
const key = try allocator.dupe(u8, entry.key_ptr.*);
|
|
||||||
const value = CachedLocation{
|
|
||||||
.name = try allocator.dupe(u8, obj.get("name").?.string),
|
|
||||||
.coords = .{
|
|
||||||
.latitude = obj.get("latitude").?.float,
|
|
||||||
.longitude = obj.get("longitude").?.float,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
try cache.put(key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn saveToFile(self: *GeoCache, file_path: []const u8) !void {
|
fn save(self: *GeoCache, writer: *std.Io.Writer) !void {
|
||||||
const file = try std.fs.cwd().createFile(file_path, .{});
|
|
||||||
defer file.close();
|
|
||||||
|
|
||||||
var buffer: [4096]u8 = undefined;
|
|
||||||
var file_writer = file.writer(&buffer);
|
|
||||||
const writer = &file_writer.interface;
|
|
||||||
|
|
||||||
try writer.writeAll("{\n");
|
try writer.writeAll("{\n");
|
||||||
|
|
||||||
var it = self.cache.iterator();
|
var it = self.cache.iterator();
|
||||||
|
|
@ -134,7 +135,7 @@ fn saveToFile(self: *GeoCache, file_path: []const u8) !void {
|
||||||
if (!first) try writer.writeAll(",\n");
|
if (!first) try writer.writeAll(",\n");
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
try writer.print(" {any}: {any}", .{
|
try writer.print(" {f}: {f}", .{
|
||||||
std.json.fmt(entry.key_ptr.*, .{}),
|
std.json.fmt(entry.key_ptr.*, .{}),
|
||||||
std.json.fmt(.{
|
std.json.fmt(.{
|
||||||
.name = entry.value_ptr.name,
|
.name = entry.value_ptr.name,
|
||||||
|
|
@ -145,6 +146,17 @@ fn saveToFile(self: *GeoCache, file_path: []const u8) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll("\n}\n");
|
try writer.writeAll("\n}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn saveToFile(self: *GeoCache, file_path: []const u8) !void {
|
||||||
|
const file = try std.fs.cwd().createFile(file_path, .{});
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
var buffer: [4096]u8 = undefined;
|
||||||
|
var file_writer = file.writer(&buffer);
|
||||||
|
const writer = &file_writer.interface;
|
||||||
|
|
||||||
|
try self.save(writer);
|
||||||
try writer.flush();
|
try writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,3 +188,90 @@ test "GeoCache miss returns null" {
|
||||||
const result = cache.get("NonExistent");
|
const result = cache.get("NonExistent");
|
||||||
try std.testing.expect(result == null);
|
try std.testing.expect(result == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "save produces valid JSON" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var cache = try GeoCache.init(allocator, null);
|
||||||
|
defer cache.deinit();
|
||||||
|
|
||||||
|
try cache.put("London", .{
|
||||||
|
.name = "London, UK",
|
||||||
|
.coords = .{ .latitude = 51.5074, .longitude = -0.1278 },
|
||||||
|
});
|
||||||
|
try cache.put("Paris", .{
|
||||||
|
.name = "Paris, France",
|
||||||
|
.coords = .{ .latitude = 48.8566, .longitude = 2.3522 },
|
||||||
|
});
|
||||||
|
|
||||||
|
var buffer: [1024]u8 = undefined;
|
||||||
|
var writer = std.Io.Writer.fixed(&buffer);
|
||||||
|
try cache.save(&writer);
|
||||||
|
|
||||||
|
const output = buffer[0..writer.end];
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, output, "London") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, output, "Paris") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, output, "51.5074") != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "load parses valid JSON" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var cache_map = std.StringHashMap(CachedLocation).init(allocator);
|
||||||
|
defer {
|
||||||
|
var it = cache_map.iterator();
|
||||||
|
while (it.next()) |entry| {
|
||||||
|
allocator.free(entry.key_ptr.*);
|
||||||
|
allocator.free(entry.value_ptr.name);
|
||||||
|
}
|
||||||
|
cache_map.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const json =
|
||||||
|
\\{
|
||||||
|
\\ "London": {"name": "London, UK", "latitude": 51.5074, "longitude": -0.1278},
|
||||||
|
\\ "Paris": {"name": "Paris, France", "latitude": 48.8566, "longitude": 2.3522}
|
||||||
|
\\}
|
||||||
|
;
|
||||||
|
|
||||||
|
try load(allocator, &cache_map, json);
|
||||||
|
|
||||||
|
const london = cache_map.get("London");
|
||||||
|
try std.testing.expect(london != null);
|
||||||
|
try std.testing.expectApproxEqAbs(@as(f64, 51.5074), london.?.coords.latitude, 0.0001);
|
||||||
|
|
||||||
|
const paris = cache_map.get("Paris");
|
||||||
|
try std.testing.expect(paris != null);
|
||||||
|
try std.testing.expectApproxEqAbs(@as(f64, 48.8566), paris.?.coords.latitude, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "save and load round-trip" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var cache1 = try GeoCache.init(allocator, null);
|
||||||
|
defer cache1.deinit();
|
||||||
|
|
||||||
|
try cache1.put("Berlin", .{
|
||||||
|
.name = "Berlin, Germany",
|
||||||
|
.coords = .{ .latitude = 52.5200, .longitude = 13.4050 },
|
||||||
|
});
|
||||||
|
|
||||||
|
var buffer: [1024]u8 = undefined;
|
||||||
|
var writer = std.Io.Writer.fixed(&buffer);
|
||||||
|
try cache1.save(&writer);
|
||||||
|
|
||||||
|
var cache2 = std.StringHashMap(CachedLocation).init(allocator);
|
||||||
|
defer {
|
||||||
|
var it = cache2.iterator();
|
||||||
|
while (it.next()) |entry| {
|
||||||
|
allocator.free(entry.key_ptr.*);
|
||||||
|
allocator.free(entry.value_ptr.name);
|
||||||
|
}
|
||||||
|
cache2.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try load(allocator, &cache2, buffer[0..writer.end]);
|
||||||
|
|
||||||
|
const berlin = cache2.get("Berlin");
|
||||||
|
try std.testing.expect(berlin != null);
|
||||||
|
try std.testing.expectEqualStrings("Berlin, Germany", berlin.?.name);
|
||||||
|
try std.testing.expectApproxEqAbs(@as(f64, 52.5200), berlin.?.coords.latitude, 0.0001);
|
||||||
|
try std.testing.expectApproxEqAbs(@as(f64, 13.4050), berlin.?.coords.longitude, 0.0001);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue