Skip to content
This repository was archived by the owner on Apr 3, 2026. It is now read-only.

Commit fdd5555

Browse files
committed
Add slice and implement get/set unsafe for tuple/list
1 parent edcf2f8 commit fdd5555

1 file changed

Lines changed: 67 additions & 16 deletions

File tree

py.zig

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,12 @@ pub const Int = extern struct {
10191019
return c.PyLong_CheckExact(@as([*c]c.PyObject, @constCast(@ptrCast(obj)))) != 0;
10201020
}
10211021

1022+
// Returns 1 if o is an index integer (has the nb_index slot of the tp_as_number structure filled in), and 0 otherwise.
1023+
// This function always succeeds.
1024+
pub inline fn checkIndex(obj: *const Object) bool {
1025+
return c.PyIndex_Check(@as([*c]c.PyObject, @constCast(@ptrCast(obj)))) != 0;
1026+
}
1027+
10221028
// Convert to the given zig type
10231029
pub inline fn as(self: *Int, comptime T: type) !T {
10241030
comptime var error_value = -1;
@@ -1276,6 +1282,34 @@ pub const Bytes = extern struct {
12761282
// TODO: finish
12771283
};
12781284

1285+
pub const Slice = extern struct {
1286+
// The underlying python structure
1287+
impl: c.PySliceObject,
1288+
1289+
// Import the object protocol
1290+
pub usingnamespace ObjectProtocol(@This());
1291+
1292+
// Return true if ob is a slice object; ob must not be NULL. This function always succeeds.
1293+
pub inline fn check(obj: *const Object) bool {
1294+
return c.PySlice_Check(@as([*c]c.PyObject, @constCast(@ptrCast(obj)))) != 0;
1295+
}
1296+
1297+
// Return a new slice object with the given values.
1298+
// The start, stop, and step parameters are used as the values of the slice object attributes of the same names.
1299+
// Any of the values may be NULL, in which case the None will be used for the corresponding attribute.
1300+
// Returns new reference
1301+
pub inline fn new(start: ?*Object, stop: ?*Object, step: ?*Object) !*Slice {
1302+
if (newUnchecked(start, stop, step)) |r| {
1303+
return @ptrCast(r);
1304+
}
1305+
return error.PyError;
1306+
}
1307+
1308+
pub inline fn newUnchecked(start: ?*Object, stop: ?*Object, step: ?*Object) ?*Object {
1309+
return @ptrCast(c.PySlice_New(@ptrCast(start), @ptrCast(stop), @ptrCast(step)));
1310+
}
1311+
};
1312+
12791313
pub const Tuple = extern struct {
12801314
// The underlying python structure
12811315
impl: c.PyTupleObject,
@@ -1378,10 +1412,10 @@ pub const Tuple = extern struct {
13781412
const r = try Tuple.new(n1 + n2);
13791413
errdefer r.decref();
13801414
for (0..n1) |i| {
1381-
try r.set(i, a.getUnsafe(i).?.newref());
1415+
r.setUnsafe(i, a.getUnsafe(i).?.newref());
13821416
}
13831417
for (0..n2) |i| {
1384-
try r.set(i + n1, b.getUnsafe(i).?.newref());
1418+
r.setUnsafe(i + n1, b.getUnsafe(i).?.newref());
13851419
}
13861420
return r;
13871421
}
@@ -1394,9 +1428,9 @@ pub const Tuple = extern struct {
13941428
const n = try self.size();
13951429
const r = try Tuple.new(n + 1);
13961430
errdefer r.decref();
1397-
try r.set(0, obj.newref());
1431+
r.setUnsafe(0, obj.newref());
13981432
for (0..n) |i| {
1399-
try r.set(i + 1, self.getUnsafe(i).?.newref());
1433+
r.setUnsafe(i + 1, self.getUnsafe(i).?.newref());
14001434
}
14011435
return r;
14021436
}
@@ -1409,9 +1443,9 @@ pub const Tuple = extern struct {
14091443
const r = try Tuple.new(n + 1);
14101444
errdefer r.decref();
14111445
for (0..n) |i| {
1412-
try r.set(i, self.getUnsafe(i).?.newref());
1446+
r.setUnsafe(i, self.getUnsafe(i).?.newref());
14131447
}
1414-
try r.set(n, obj.newref());
1448+
r.setUnsafe(n, obj.newref());
14151449
return r;
14161450
}
14171451

@@ -1439,9 +1473,13 @@ pub const Tuple = extern struct {
14391473
return error.PyError;
14401474
}
14411475

1476+
// Returns borrowed reference with no error checking
14421477
pub inline fn getUnsafe(self: *Tuple, pos: usize) ?*Object {
1443-
// TODO: fix PyTuple_GET_ITEM
1444-
return @ptrCast(c.PyTuple_GetItem(@ptrCast(self), @intCast(pos)));
1478+
std.debug.assert(Tuple.check(@ptrCast(self)));
1479+
// Weird casting is because zig (correctly) thinks it goes OOB
1480+
// becaues it's defined as a single item array
1481+
const items: [*]*Object = @ptrCast(&self.impl.ob_item);
1482+
return items[pos];
14451483
}
14461484

14471485
// Insert a _stolen_ reference to object o at position pos of the tuple pointed to by p.
@@ -1459,9 +1497,10 @@ pub const Tuple = extern struct {
14591497
// any reference in the tuple at position pos will be leaked.
14601498
pub inline fn setUnsafe(self: *Tuple, pos: usize, obj: *Object) void {
14611499
// The tuple struct only has one item so zig (correctly) thinks this is writing
1462-
// out of bounds. This is marked unsafe for a reason.
1463-
const r = c.PyTuple_SetItem(@ptrCast(self), @intCast(pos), @ptrCast(obj));
1464-
std.debug.assert(r >= 0);
1500+
// out of bounds. Hence the weird cast
1501+
std.debug.assert(Tuple.check(@ptrCast(self)));
1502+
const items: [*]*Object = @ptrCast(&self.impl.ob_item);
1503+
items[pos] = @ptrCast(obj);
14651504
}
14661505

14671506
// Return the slice of the tuple pointed to by p between low and high,
@@ -1557,8 +1596,9 @@ pub const List = extern struct {
15571596

15581597
// Get borrowed refernce to list item at index without type or bounds checking
15591598
// Calls PyList_GET_ITEM(self, index).
1560-
pub inline fn getUnsafe(self: *List, index: isize) ?*Object {
1561-
return c.PyList_GET_ITEM(@ptrCast(self), index);
1599+
pub inline fn getUnsafe(self: *List, index: usize) ?*Object {
1600+
std.debug.assert(List.check(@ptrCast(self)));
1601+
return @ptrCast(self.impl.ob_item[index]);
15621602
}
15631603

15641604
// Set the item at index index in list to item. Return 0 on success.
@@ -1582,8 +1622,9 @@ pub const List = extern struct {
15821622
// content. This macro “steals” a reference to item, and, unlike PyList_SetItem(),
15831623
// does not discard a reference to any item that is being replaced;
15841624
// any reference in list at position i will be leaked.
1585-
pub inline fn setUnsafe(self: *List, index: isize, item: *Object) c_int {
1586-
return c.PyList_SET_ITEM(@ptrCast(self), index, item);
1625+
pub inline fn setUnsafe(self: *List, index: isize, item: *Object) void {
1626+
std.debug.assert(List.check(@ptrCast(self)));
1627+
self.impl.ob_item[index] = @ptrCast(item);
15871628
}
15881629

15891630
// Insert the item item into list list in front of index index.
@@ -1950,6 +1991,16 @@ pub const Set = extern struct {
19501991
return c.PySet_CheckExact(@as([*c]c.PyObject, @constCast(@ptrCast(obj)))) != 0;
19511992
}
19521993

1994+
// Return true if p is a set object, a frozenset object, or an instance of a subtype. This function always succeeds.
1995+
pub inline fn checkAny(obj: *const Object) bool {
1996+
return c.PyAnySet_Check(@as([*c]c.PyObject, @constCast(@ptrCast(obj))));
1997+
}
1998+
1999+
// Return true if p is a set object or a frozenset object but not an instance of a subtype. This function always succeeds.
2000+
pub inline fn checkAnyExact(obj: *const Object) bool {
2001+
return c.PyAnySet_CheckExact(@as([*c]c.PyObject, @constCast(@ptrCast(obj))));
2002+
}
2003+
19532004
// Return a new set containing objects returned by the iterable.
19542005
// The iterable may be NULL to create a new empty set.
19552006
// Raise TypeError if iterable is not actually iterable.
@@ -2210,7 +2261,7 @@ pub const Method = extern struct {
22102261

22112262
// Return true if o is a method object (has type PyMethod_Type).
22122263
// The parameter must not be NULL. This function always succeeds.
2213-
pub fn check(obj: *Object) bool {
2264+
pub fn check(obj: *const Object) bool {
22142265
return c.PyMethod_Check(@as([*c]c.PyObject, @constCast(@ptrCast(obj)))) != 0;
22152266
}
22162267

0 commit comments

Comments
 (0)