From 6c2e06ed20cdea1a67629554d8aa1d5fcda030f9 Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Wed, 2 Sep 2026 08:17:42 +0200 Subject: Implement sequences and tuples --- src/dict/Watcher.zig | 62 ++++++++++++++++++++++ src/dict/root.zig | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 src/dict/Watcher.zig create mode 100644 src/dict/root.zig (limited to 'src/dict') diff --git a/src/dict/Watcher.zig b/src/dict/Watcher.zig new file mode 100644 index 0000000..317a269 --- /dev/null +++ b/src/dict/Watcher.zig @@ -0,0 +1,62 @@ +const std = @import("std"); +const c = @import("c"); +const zpy = @import("../root.zig"); + +const Self = @This(); + +id: c_int, + +pub const Event = enum(u32) { + added = c.PyDict_EVENT_ADDED, + modified = c.PyDict_EVENT_MODIFIED, + deleted = c.PyDict_EVENT_DELETED, + cloned = c.PyDict_EVENT_CLONED, + cleared = c.PyDict_EVENT_CLEARED, + deallocated = c.PyDict_EVENT_DEALLOCATED, +}; + +pub const Callback = fn (Event, *zpy.Dict, *zpy.Object, *zpy.Object) error{Exception}!void; + +pub fn add(callback: Callback) !Self { + const wrapper = struct { + pub fn wrapper( + event: c_uint, + dict: [*c]c.PyObject, + key: [*c]c.PyObject, + value: [*c]c.PyObject, + ) callconv(.c) c_int { + return if (std.meta.isError(callback( + @enumFromInt(event), + @ptrCast(dict), + @ptrCast(key), + @ptrCast(value), + ))) -1 else 0; + } + }.wrapper; + + const result = c.PyDict_AddWatcher(&wrapper); + + if (result == -1) { + return error.Exception; + } + + return .{ .id = result }; +} + +pub fn clear(self: Self) !void { + if (c.PyDict_Clear(self.id) == -1) { + return error.Exception; + } +} + +pub fn watch(self: Self, dict: *zpy.Dict) !void { + if (c.PyDict_Watch(self.id, @ptrCast(dict)) == -1) { + return error.Exception; + } +} + +pub fn unwatch(self: Self, dict: *zpy.Dict) !void { + if (c.PyDict_Unwatch(self.id, @ptrCast(dict)) == -1) { + return error.Exception; + } +} diff --git a/src/dict/root.zig b/src/dict/root.zig new file mode 100644 index 0000000..169add1 --- /dev/null +++ b/src/dict/root.zig @@ -0,0 +1,145 @@ +const std = @import("std"); +const c = @import("c"); + +const zpy = @import("../root.zig"); + +pub const Dict = extern struct { + const Self = @This(); + + data: c.PyObject, + + pub const Watcher = @import("Watcher.zig"); + + pub const Key = union(enum) { + string: [*c]const u8, + object: *zpy.Object, + }; + + pub fn new() !*Self { + return @ptrCast(c.PyDict_New() orelse return error.Exception); + } + + pub fn clear(self: *Self) void { + c.PyDict_Clear(self.object.ptr); + } + + pub fn contains(self: *const Self, key: Key) bool { + return switch (key) { + .string => |str| c.PyDict_ContainsString(@ptrCast(self), str), + .object => |obj| c.PyDict_Contains(@ptrCast(self), @ptrCast(obj)), + } == 1; + } + + pub fn copy(self: *const Self) *Self { + return @ptrCast(c.PyDict_Copy(@ptrCast(self))); + } + + pub fn set(self: *Self, key: Key, value: zpy.Object) !void { + const ret = switch (key) { + .string => |str| c.PyDict_SetItemString(self.object.ptr, str, value.ptr), + .object => |obj| c.PyDict_SetItem(self.object.ptr, obj.ptr, value.ptr), + }; + + if (ret == -1) return error.Exception; + } + + pub fn get(self: *const Self, key: Key) ?*zpy.Object { + return @ptrCast(switch (key) { + .string => |str| c.PyDict_GetItemString(@ptrCast(@constCast(self)), str), + .object => |obj| c.PyDict_GetItem(@ptrCast(@constCast(self)), @ptrCast(obj)), + }); + } + + pub fn delete(self: *Self, key: Key) !void { + const ret = switch (key) { + .string => |str| c.PyDict_DelItemString(@ptrCast(self), str), + .object => |obj| c.PyDict_DelItem(@ptrCast(self), @ptrCast(obj)), + }; + + if (ret == -1) return error.Exception; + } + + pub fn setDefault(self: *Self, key: *zpy.Object, default: *zpy.Object) *zpy.Object { + return @ptrCast(c.PyDict_SetDefault( + @ptrCast(self), + @ptrCast(key), + @ptrCast(default), + )); + } + + pub fn pop(self: *Self, key: Key) ?zpy.Object { + var result: ?*c.PyObject = undefined; + + switch (key) { + .string => |str| c.PyDict_PopString(@ptrCast(self), str, &result), + .object => |obj| c.PyDict_Pop(@ptrCast(self), @ptrCast(obj), &result), + } + + return result; + } + + pub fn items(self: *const Self) zpy.List { + return @ptrCast(c.PyDict_Items(@ptrCast(@constCast(self)))); + } + + pub fn keys(self: *const Self) zpy.List { + return @ptrCast(c.PyDict_Keys(@ptrCast(@constCast(self)))); + } + + pub fn values(self: *const Self) zpy.List { + return @ptrCast(c.PyDict_Values(@ptrCast(@constCast(self)))); + } + + pub fn size(self: *const Self) usize { + return @intCast(c.PyDict_Size(@ptrCast(@constCast(self)))); + } + + pub const Iterator = struct { + dict: *Dict, + position: c.Py_ssize_t = 0, + + pub const Pair = struct { + key: *zpy.Object, + value: *zpy.Object, + }; + + pub fn next(self: *@This()) ?Pair { + var pair: Pair = undefined; + + if (c.PyDict_Next( + @ptrCast(self.dict), + &self.position, + @ptrCast(&pair.key), + @ptrCast(&pair.value), + ) == 1) { + return pair; + } + + return null; + } + }; + + pub fn iterator(self: *Self) Iterator { + return .{ .dict = self }; + } + + pub fn merge(self: *Self, other: *Self) !void { + if (c.PyDict_Merge( + @ptrCast(self), + @ptrCast(other), + 0, + ) == -1) { + return error.Exception; + } + } + + pub fn update(self: *Self, other: *Self) !void { + if (c.PyDict_Merge( + @ptrCast(self), + @ptrCast(other), + 1, + ) == -1) { + return error.Exception; + } + } +}; -- cgit v1.2.3-70-g09d2