Skip to content

Commit 8a6b15b

Browse files
committed
Fix conversion of step range to slice with negative step size
1 parent c8ba36d commit 8a6b15b

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

ext/pycall/pycall.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,16 +1777,36 @@ pycall_pyslice_from_ruby(VALUE obj)
17771777
rb_raise(rb_eTypeError, "unexpected argument type %s (expected Range or Enumerator generated by Range#step)", rb_class2name(CLASS_OF(obj)));
17781778
}
17791779

1780-
if (!exclude_end) {
1781-
ssize_t end_i = NUM2SSIZET(end);
1782-
switch (end_i) {
1783-
case -1:
1784-
end = Qnil;
1785-
break;
1786-
1787-
default:
1788-
end = SSIZET2NUM(end_i + 1); /* TODO: limit check */
1789-
break;
1780+
if (!NIL_P(step) && NUM2SSIZET(step) < 0) {
1781+
if (!NIL_P(end)) {
1782+
if (!exclude_end) {
1783+
ssize_t end_i = NUM2SSIZET(end);
1784+
switch (end_i) {
1785+
case 0:
1786+
end = Qnil;
1787+
break;
1788+
1789+
default:
1790+
end = SSIZET2NUM(end_i - 1); /* TODO: limit check */
1791+
break;
1792+
}
1793+
}
1794+
}
1795+
}
1796+
else {
1797+
if (!NIL_P(end)) {
1798+
if (!exclude_end) {
1799+
ssize_t end_i = NUM2SSIZET(end);
1800+
switch (end_i) {
1801+
case -1:
1802+
end = Qnil;
1803+
break;
1804+
1805+
default:
1806+
end = SSIZET2NUM(end_i + 1); /* TODO: limit check */
1807+
break;
1808+
}
1809+
}
17901810
}
17911811
}
17921812

spec/pycall/pyobject_wrapper_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ module PyCall
149149
expect(list[0..0]).to eq(PyCall::List.new([1]))
150150
expect(list[0...0]).to eq(PyCall::List.new([]))
151151
expect(list[0..-1]).to eq(PyCall::List.new([*1..10]))
152+
expect(list[nil..nil]).to eq(PyCall::List.new([*1..10]))
152153
expect(list[0...-1]).to eq(PyCall::List.new([*1..9]))
153154
expect(list[1..-2]).to eq(PyCall::List.new([*2..9]))
154155
expect(list[1...-2]).to eq(PyCall::List.new([*2..8]))
@@ -160,6 +161,11 @@ module PyCall
160161
list = PyCall::List.new([*1..10])
161162
expect(list[(1..-1).step(2)]).to eq(PyCall::List.new([2, 4, 6, 8, 10]))
162163
expect(list[(1..-2).step(2)]).to eq(PyCall::List.new([2, 4, 6, 8]))
164+
expect(list[(nil..nil).step(-1)]).to eq(PyCall::List.new([*1..10].reverse))
165+
expect(list[(-1..0).step(-1)]).to eq(PyCall::List.new([*1..10].reverse))
166+
expect(list[(-1...0).step(-1)]).to eq(PyCall::List.new([*2..10].reverse))
167+
expect(list[(-2..2).step(-2)]).to eq(PyCall::List.new([9, 7, 5, 3]))
168+
expect(list[(-2...2).step(-2)]).to eq(PyCall::List.new([9, 7, 5]))
163169
end
164170
end
165171
end

0 commit comments

Comments
 (0)