╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ event.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
237 switch (@typeInfo(Data)) { 238 .@"struct" => |struct_info| { 239 inline for (struct_info.fields) |field| { 240 try upsertField(DB, hash_kind, map, field.name, field.type, @field(data, field.name)); 241 } 242 }, 243 else => @compileError("upsert expects a struct"), 244 } 245 } 246 247 fn upsertField( 248 comptime DB: type, 249 comptime hash_kind: hash.HashKind, 250 map: DB.HashMap(.read_write), 251 comptime field_name: []const u8, 252 comptime Field: type, 253 value: Field, 254 ) !void { 255 const key = hash.hashInt(hash_kind, field_name); 256 257 switch (@typeInfo(Field)) { 258 .pointer => |pointer_info| { 259 if (pointer_info.size == .slice and pointer_info.child == u8) { 260 try upsertBytes(DB, hash_kind, map, key, value); 261 } else { 262 @compileError("unsupported upsert field type: " ++ @typeName(Field)); 263 } 264 }, 265 .array => |array_info| { 266 if (array_info.child == u8) { 267 try upsertBytes(DB, hash_kind, map, key, &value); 268 } else { 269 @compileError("unsupported upsert field type: " ++ @typeName(Field)); 270 } 271 }, 272 .int => |int_info| switch (int_info.signedness) { 273 .unsigned => { 274 if (try map.getCursor(key)) |value_cursor| { 275 if (try value_cursor.readUint() == value) { 276 return; 277 } 278 } 279 280 try map.put(key, .{ .uint = value }); 281 }, 282 .signed => { 283 if (try map.getCursor(key)) |value_cursor| { 284 if (try value_cursor.readInt() == value) { 285 return; 286 } 287 } 288 289 try map.put(key, .{ .int = value }); 290 }, 291 }, 292 else => @compileError("unsupported upsert field type: " ++ @typeName(Field)), 293 } 294 } 295 296 fn upsertBytes( 297 comptime DB: type, 298 comptime hash_kind: hash.HashKind, 299 map: DB.HashMap(.read_write), 300 key: hash.HashInt(hash_kind), 301 value: []const u8, 302 ) !void { 303 var existing_cursor_maybe = try map.getCursor(key); 304 if (existing_cursor_maybe) |*existing_cursor| { 305 if (try bytesEqual(DB, existing_cursor, value)) { 306 return; 307 } 308 } 309 310 var value_cursor = try map.putCursor(key); 311 var write_buffer: [1024]u8 = undefined; 312 var writer = try value_cursor.writer(&write_buffer); 313 try writer.interface.writeAll(value); 314 try writer.finish(); 315 } 316 317 fn bytesEqual( 318 comptime DB: type, 319 cursor: *DB.Cursor(.read_only), 320 value: []const u8, 321 ) !bool { 322 var read_buffer: [1024]u8 = undefined; 323 var reader = try cursor.reader(&read_buffer); 324 if (reader.size != value.len) { 325 return false; 326 } 327 328 var chunk_buffer: [1024]u8 = undefined; 329 var offset: usize = 0; 330 while (offset < value.len) { 331 const chunk_len = @min(chunk_buffer.len, value.len - offset); 332 try reader.interface.readSliceAll(chunk_buffer[0..chunk_len]); 333 if (!std.mem.eql(u8, chunk_buffer[0..chunk_len], value[offset .. offset + chunk_len])) { 334 return false; 335 } 336 offset += chunk_len; 337 } 338 339 return true; 340 } 341