]> gitweb.ps.run Git - ziglmdb/blob - src/lmdb.zig
rename typeinfo.Pointer
[ziglmdb] / src / lmdb.zig
1 const std = @import("std");
2 const lmdb = @cImport(@cInclude("lmdb.h"));
3
4 pub usingnamespace lmdb;
5
6 pub const Cursor = struct {
7     const Self = @This();
8
9     pub const Flags = enum(c_uint) {
10         First = lmdb.MDB_FIRST,
11         FirstDup = lmdb.MDB_FIRST_DUP,
12         GetBoth = lmdb.MDB_GET_BOTH,
13         GetBothRange = lmdb.MDB_GET_BOTH_RANGE,
14         GetCurrent = lmdb.MDB_GET_CURRENT,
15         GetMultiple = lmdb.MDB_GET_MULTIPLE,
16         Last = lmdb.MDB_LAST,
17         LastDup = lmdb.MDB_LAST_DUP,
18         Next = lmdb.MDB_NEXT,
19         NextDup = lmdb.MDB_NEXT_DUP,
20         NextMultiple = lmdb.MDB_NEXT_MULTIPLE,
21         NextNodup = lmdb.MDB_NEXT_NODUP,
22         Prev = lmdb.MDB_PREV,
23         PrevDup = lmdb.MDB_PREV_DUP,
24         PrevNodup = lmdb.MDB_PREV_NODUP,
25         Set = lmdb.MDB_SET,
26         SetKey = lmdb.MDB_SET_KEY,
27         SetRange = lmdb.MDB_SET_RANGE,
28     };
29
30     ptr: ?*lmdb.MDB_cursor = undefined,
31
32     pub fn close(self: Self) void {
33         lmdb.mdb_cursor_close(self.ptr);
34     }
35
36     pub fn put(self: Self, k: anytype, v: anytype) !void {
37         var key = lmdb.MDB_val{
38             .mv_size = @sizeOf(@TypeOf(k)),
39             .mv_data = @constCast(@ptrCast(&k)),
40         };
41         var val = lmdb.MDB_val{
42             .mv_size = @sizeOf(@TypeOf(v)),
43             .mv_data = @constCast(@ptrCast(&v)),
44         };
45         switch (lmdb.mdb_cursor_put(self.ptr, &key, &val, 0)) {
46             0 => {},
47             else => |err| {
48                 _ = err;
49                 return error.CursorPut;
50             },
51         }
52     }
53
54     pub fn get(self: Self, k: anytype, comptime V: type, flags: Flags) !?V {
55         const k_ti = @typeInfo(@TypeOf(k));
56         const K = k_ti.pointer.child;
57
58         var key = lmdb.MDB_val{
59             .mv_size = @sizeOf(K),
60             .mv_data = @constCast(@ptrCast(k)),
61         };
62         var val: lmdb.MDB_val = undefined;
63         return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
64             0 => {
65                 const ptr = @as(*K, @constCast(k));
66                 ptr.* = std.mem.bytesToValue(K, key.mv_data.?);
67                 return std.mem.bytesToValue(V, val.mv_data.?);
68             },
69             lmdb.MDB_NOTFOUND => null,
70             else => |err| {
71                 _ = err;
72                 return error.CursorGet;
73             },
74         };
75     }
76
77     pub fn del(self: Self, k: anytype) !void {
78         var key = lmdb.MDB_val{
79             .mv_size = @sizeOf(@TypeOf(k)),
80             .mv_data = @constCast(@ptrCast(&k)),
81         };
82         switch (lmdb.mdb_cursor_del(self.ptr, &key, 0)) {
83             0 => {},
84             else => |err| {
85                 _ = err;
86                 return error.CursorDel;
87             },
88         }
89     }
90
91     pub fn has(self: Self, k: anytype, flags: Flags) !bool {
92         const k_ti = @typeInfo(@TypeOf(k));
93         const K = k_ti.pointer.child;
94
95         var key = lmdb.MDB_val{
96             .mv_size = @sizeOf(K),
97             .mv_data = @constCast(@ptrCast(k)),
98         };
99         var val: lmdb.MDB_val = undefined;
100         return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
101             0 => {
102                 return true;
103             },
104             lmdb.MDB_NOTFOUND => {
105                 return false;
106             },
107             else => {
108                 return error.CursorHas;
109             },
110         };
111     }
112 };
113
114 pub const Dbi = struct {
115     const Self = @This();
116
117     ptr: lmdb.MDB_dbi = undefined,
118     txn: Txn = undefined,
119     env: Env = undefined,
120
121     pub fn close(self: Self) void {
122         // TODO: necessary?
123         lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
124     }
125
126     pub fn cursor(self: Self) !Cursor {
127         var result = Cursor{};
128
129         return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
130             0 => result,
131             else => error.DbiCursor,
132         };
133     }
134
135     pub fn put(self: Self, k: anytype, v: anytype) !void {
136         var key = lmdb.MDB_val{
137             .mv_size = @sizeOf(@TypeOf(k)),
138             .mv_data = @constCast(@ptrCast(&k)),
139         };
140         var val = lmdb.MDB_val{
141             .mv_size = @sizeOf(@TypeOf(v)),
142             .mv_data = @constCast(@ptrCast(&v)),
143         };
144         switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
145             0 => {},
146             else => |err| {
147                 _ = err;
148                 return error.DbiPut;
149             },
150         }
151     }
152
153     pub fn get(self: Self, k: anytype, comptime V: type) !V {
154         var key = lmdb.MDB_val{
155             .mv_size = @sizeOf(@TypeOf(k)),
156             .mv_data = @constCast(@ptrCast(&k)),
157         };
158         var val: lmdb.MDB_val = undefined;
159         return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
160             0 => {
161                 return std.mem.bytesToValue(V, val.mv_data.?);
162             },
163             lmdb.MDB_NOTFOUND => error.NotFound,
164             else => |err| {
165                 _ = err;
166                 return error.DbiGet;
167             },
168         };
169     }
170
171     pub fn del(self: Self, k: anytype) !void {
172         var key = lmdb.MDB_val{
173             .mv_size = @sizeOf(@TypeOf(k)),
174             .mv_data = @constCast(@ptrCast(&k)),
175         };
176         switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
177             0 => {},
178             else => |err| {
179                 _ = err;
180                 return error.DbiDel;
181             },
182         }
183     }
184
185     pub fn has(self: Self, k: anytype) !bool {
186         var key = lmdb.MDB_val{
187             .mv_size = @sizeOf(@TypeOf(k)),
188             .mv_data = @constCast(@ptrCast(&k)),
189         };
190         var val: lmdb.MDB_val = undefined;
191         return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
192             0 => {
193                 return true;
194             },
195             lmdb.MDB_NOTFOUND => {
196                 return false;
197             },
198             else => |err| {
199                 std.debug.print("[{}]\n", .{err});
200                 return error.DbiHas;
201             },
202         };
203     }
204 };
205
206 pub const Txn = struct {
207     ptr: ?*lmdb.MDB_txn = undefined,
208     env: Env = undefined,
209
210     pub fn dbi(self: Txn, name: [:0]const u8) !Dbi {
211         var result = Dbi{ .env = self.env, .txn = self };
212         // TODO: lmdb.MDB_INTEGERKEY?
213         switch (lmdb.mdb_dbi_open(self.ptr, @ptrCast(name), lmdb.MDB_CREATE, &result.ptr)) {
214             0 => return result,
215             else => |err| {
216                 _ = err;
217                 return error.DbiOpen;
218             },
219         }
220     }
221
222     pub fn commit(self: Txn) !void {
223         switch (lmdb.mdb_txn_commit(self.ptr)) {
224             0 => {},
225             lmdb.MDB_MAP_FULL => {
226                 _ = lmdb.mdb_env_set_mapsize(self.env.ptr, 0);
227                 return error.TxnCommitMapFull;
228             },
229             else => |err| {
230                 _ = err;
231                 return error.TxnCommit;
232             },
233         }
234     }
235
236     pub fn abort(self: Txn) void {
237         lmdb.mdb_txn_abort(self.ptr);
238     }
239 };
240
241 pub const Env = struct {
242     ptr: ?*lmdb.MDB_env = undefined,
243
244     pub fn open(name: [:0]const u8, size: lmdb.mdb_size_t) !Env {
245         var result = Env{};
246
247         _ = lmdb.mdb_env_create(&result.ptr);
248         _ = lmdb.mdb_env_set_maxdbs(result.ptr, 10);
249         _ = lmdb.mdb_env_set_mapsize(result.ptr, size);
250         const res = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_WRITEMAP, 0o664);
251         // _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664);
252
253         if (res != 0) {
254             return error.EnvOpen;
255         } else {
256             return result;
257         }
258     }
259
260     pub fn close(self: Env) void {
261         lmdb.mdb_env_close(self.ptr);
262     }
263
264     pub fn txn(self: Env) !Txn {
265         var result = Txn{ .env = self };
266         switch (lmdb.mdb_txn_begin(self.ptr, null, 0, &result.ptr)) {
267             0 => return result,
268             else => |err| {
269                 _ = err;
270                 return error.TxnOpen;
271             },
272         }
273     }
274
275     pub fn sync(self: Env) !void {
276         switch (lmdb.mdb_env_sync(self.ptr, 1)) {
277             0 => {},
278             else => |err| {
279                 _ = err;
280                 return error.EnvSync;
281             },
282         }
283     }
284 };
285
286 test "basic" {
287     var env = try Env.open("db", 1024 * 1024 * 1);
288     // env.sync();
289     defer env.close();
290
291     var txn = try env.txn();
292     defer txn.commit() catch {};
293
294     const Value = struct {
295         i: i64 = 123,
296         s: [16]u8 = undefined,
297     };
298
299     var dbi = try txn.dbi("abc");
300
301     const idx: u64 = 1;
302
303     std.debug.print("has?: {}\n", .{try dbi.has(idx)});
304
305     var val = dbi.get(idx, Value) catch Value{ .i = 5 };
306     std.debug.print("{}\n", .{val});
307
308     val.i += 1;
309
310     try dbi.put(idx, val);
311 }
312
313 test "cursor" {
314     var env = try Env.open("db", 1024 * 1024 * 1);
315     // env.sync();
316     defer env.close();
317
318     var txn = try env.txn();
319     defer txn.commit() catch {};
320
321     const Value = struct {
322         i: i64 = 123,
323         s: [16]u8 = undefined,
324     };
325
326     var dbi = try txn.dbi("def");
327
328     for (0..10) |i| {
329         try dbi.put(@as(u64, i), Value{ .i = @intCast(i + 23) });
330     }
331
332     var cursor = try dbi.cursor();
333     defer cursor.close();
334
335     var key: u64 = undefined;
336     {
337         const val = try cursor.get(&key, Value, .First);
338         std.debug.print("{}: {?}\n", .{ key, val });
339     }
340
341     while (try cursor.get(&key, Value, .Next)) |val| {
342         std.debug.print("{}: {?}\n", .{ key, val });
343     }
344 }
345
346 // pub fn get(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, comptime T: type) ?T {
347 //     var key = lmdb.MDB_val{
348 //         .mv_size = @sizeOf(@TypeOf(k)),
349 //         .mv_data = @constCast(@ptrCast(&k)),
350 //     };
351 //     var val: lmdb.MDB_val = undefined;
352 //     return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
353 //         0 => @as(?*align(1) T, @alignCast(@ptrCast(val.mv_data))).?.*,
354 //         else => |err| {
355 //             std.debug.print("get err: {}\n", .{err});
356 //             return null;
357 //         },
358 //     };
359 // }
360
361 // pub fn put(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, v: anytype) void {
362 //     var key = lmdb.MDB_val{
363 //         .mv_size = @sizeOf(@TypeOf(k)),
364 //         .mv_data = @constCast(@ptrCast(&k)),
365 //     };
366 //     var val = lmdb.MDB_val{
367 //         .mv_size = @sizeOf(@TypeOf(v)),
368 //         .mv_data = @constCast(@ptrCast(&v)),
369 //     };
370 //     switch (lmdb.mdb_put(txn, dbi, &key, &val, 0)) {
371 //         0 => {},
372 //         else => |err| {
373 //             std.debug.print("put err: {}\n", .{err});
374 //         },
375 //     }
376 // }
377
378 // pub fn del(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) void {
379 //     var key = lmdb.MDB_val{
380 //         .mv_size = @sizeOf(@TypeOf(k)),
381 //         .mv_data = @constCast(@ptrCast(&k)),
382 //     };
383 //     switch (lmdb.mdb_del(txn, dbi, &key, null)) {
384 //         0 => {},
385 //         else => |err| {
386 //             std.debug.print("del err: {}\n", .{err});
387 //         },
388 //     }
389 // }
390
391 // pub fn has(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) bool {
392 //     var key = lmdb.MDB_val{
393 //         .mv_size = @sizeOf(@TypeOf(k)),
394 //         .mv_data = @constCast(@ptrCast(&k)),
395 //     };
396 //     var val: lmdb.MDB_val = undefined;
397 //     return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
398 //         0 => true,
399 //         lmdb.MDB_NOTFOUND => false,
400 //         else => |err| {
401 //             std.debug.print("has err: {}\n", .{err});
402 //             return false;
403 //         },
404 //     };
405 // }