Skip to content

Commit

Permalink
Add PyType object (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
gatesn committed Sep 28, 2023
1 parent ef233a7 commit 2a24099
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 16 deletions.
4 changes: 2 additions & 2 deletions pydust/src/attributes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
const py = @import("pydust.zig");
const PyType = @import("pytypes.zig").PyType;
const Type = @import("pytypes.zig").Type;
const State = @import("discovery.zig").State;

pub const Attribute = struct {
Expand Down Expand Up @@ -48,7 +48,7 @@ pub fn Attributes(comptime definition: type) type {
if (def.type == .class) {
const Closure = struct {
pub fn init(module: py.PyModule) !py.PyObject {
const typedef = PyType(decl.name ++ "", def.definition);
const typedef = Type(decl.name ++ "", def.definition);
return try typedef.init(module);
}
};
Expand Down
7 changes: 5 additions & 2 deletions pydust/src/builtins.zig
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,11 @@ pub fn tuple(object: anytype) !py.PyTuple {
return py.PyTuple.unchecked(.{ .py = pytuple });
}

pub fn type_(object: anytype) !py.PyObject {
return .{ .py = ffi.Py_TYPE(py.object(object).py) orelse return PyError.PyRaised };
pub fn type_(object: anytype) !py.PyType {
return .{ .obj = .{ .py = @as(
?*ffi.PyObject,
@ptrCast(@alignCast(ffi.Py_TYPE(py.object(object).py))),
) orelse return PyError.PyRaised } };
}

// TODO(ngates): What's the easiest / cheapest way to do this?
Expand Down
1 change: 0 additions & 1 deletion pydust/src/pydust.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const State = @import("discovery.zig").State;
const Module = @import("modules.zig").Module;
const types = @import("types.zig");
const pytypes = @import("pytypes.zig");
const PyType = pytypes.PyType;
const funcs = @import("functions.zig");
const tramp = @import("trampoline.zig");

Expand Down
3 changes: 1 addition & 2 deletions pydust/src/pytypes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const funcs = @import("functions.zig");
const PyError = @import("errors.zig").PyError;
const PyMemAllocator = @import("mem.zig").PyMemAllocator;
const tramp = @import("trampoline.zig");
const Type = std.builtin.Type;

/// For a given Pydust class definition, return the encapsulating PyType struct.
pub fn PyTypeStruct(comptime definition: type) type {
Expand All @@ -35,7 +34,7 @@ pub fn PyTypeStruct(comptime definition: type) type {
}

/// Discover a Pydust class definition.
pub fn PyType(comptime name: [:0]const u8, comptime definition: type) type {
pub fn Type(comptime name: [:0]const u8, comptime definition: type) type {
return struct {
const qualifiedName: [:0]const u8 = blk: {
const moduleName = State.getIdentifier(State.getContaining(definition, .module)).name;
Expand Down
1 change: 1 addition & 0 deletions pydust/src/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ pub usingnamespace @import("types/module.zig");
pub usingnamespace @import("types/obj.zig");
pub usingnamespace @import("types/str.zig");
pub usingnamespace @import("types/tuple.zig");
pub usingnamespace @import("types/type.zig");
9 changes: 0 additions & 9 deletions pydust/src/types/obj.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ const str = @import("str.zig");
const py = @import("../pydust.zig");
const PyError = @import("../errors.zig").PyError;

/// PyTypeObject exists in Limited API only as an opaque pointer.
pub const PyType = extern struct {
obj: PyObject,

pub fn getQualifiedName(self: PyType) !py.PyString {
return py.PyString.of(ffi.PyType_GetQualName(self.obj.py) orelse return PyError.PyRaised);
}
};

pub const PyObject = extern struct {
py: *ffi.PyObject,

Expand Down
60 changes: 60 additions & 0 deletions pydust/src/types/type.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const std = @import("std");
const py = @import("../pydust.zig");
const PyObjectMixin = @import("./obj.zig").PyObjectMixin;
const ffi = py.ffi;
const PyError = @import("../errors.zig").PyError;

/// Wrapper for Python PyType.
/// Since PyTypeObject is opaque in the Python API, we cannot use the PyObject mixin.
/// Instead, we re-implement the mixin functions and insert @ptrCast where necessary.
pub const PyType = extern struct {
obj: py.PyObject,

pub usingnamespace PyObjectMixin("type", "PyType", @This());

pub fn name(self: PyType) !py.PyString {
return py.PyString.unchecked(.{
.py = ffi.PyType_GetName(typePtr(self.obj.py)) orelse return PyError.PyRaised,
});
}

pub fn qualifiedName(self: PyType) !py.PyString {
return py.PyString.unchecked(.{
.py = ffi.PyType_GetQualName(typePtr(self.obj.py)) orelse return PyError.PyRaised,
});
}

fn typePtr(obj: *ffi.PyObject) *ffi.PyTypeObject {
return @alignCast(@ptrCast(obj));
}

fn objPtr(obj: *ffi.PyTypeObject) *ffi.PyObject {
return @alignCast(@ptrCast(obj));
}
};

test "PyType" {
py.initialize();
defer py.finalize();

const StringIO = try PyType.checked(try py.importFrom("io", "StringIO"));
defer StringIO.decref();
try std.testing.expectEqualSlices(u8, "StringIO", try (try StringIO.name()).asSlice());

const sio = try StringIO.obj.call0();
defer sio.decref();
const sioType = try py.type_(sio);
try std.testing.expectEqualSlices(u8, "StringIO", try (try sioType.name()).asSlice());
}

0 comments on commit 2a24099

Please sign in to comment.