ext/pycall/pycall.c in pycall-1.1.0.rc1 vs ext/pycall/pycall.c in pycall-1.2.0.beta1
- old
+ new
@@ -450,11 +450,11 @@
}
static inline PyTypeObject*
try_get_pytypeobj_ptr(VALUE obj)
{
- if (is_pycall_pytypeptr(obj)) return NULL;
+ if (!is_pycall_pytypeptr(obj)) return NULL;
return (PyTypeObject*)DATA_PTR(obj);
}
static inline PyTypeObject *
check_get_pytypeobj_ptr(VALUE obj)
@@ -539,10 +539,24 @@
if (is_pycall_pyptr(other))
return pycall_pyptr_is_kind_of(other, obj);
return Qfalse;
}
+static VALUE
+pycall_pytypeptr_subclass_p(VALUE obj, VALUE other)
+{
+ PyTypeObject* pytype = get_pytypeobj_ptr(obj);
+ if (is_pycall_pyptr(other)) {
+ PyTypeObject* pytype_other = try_get_pytypeobj_ptr(other);
+ if (pytype_other) {
+ int res = Py_API(PyObject_IsSubclass)((PyObject *)pytype, (PyObject *)pytype_other);
+ return res ? Qtrue : Qfalse;
+ }
+ }
+ return Qfalse;
+}
+
/* ==== PyCall::LibPython::API ==== */
static VALUE
pycall_libpython_api_get_builtins_module_ptr(VALUE mod)
{
@@ -1275,15 +1289,43 @@
return pyobj;
}
/* ==== PyCall::Conversion ==== */
+static int
+get_mapped_ancestor_class_iter(VALUE key, VALUE value, VALUE arg)
+{
+ VALUE *args = (VALUE *)arg;
+ if (RTEST(pycall_pytypeptr_subclass_p(args[0], key))) {
+ args[1] = value;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
+pycall_python_type_mapping_get_mapped_ancestor_class(VALUE pytypeptr)
+{
+ VALUE args[2];
+ args[0] = pytypeptr;
+ args[1] = Qnil;
+
+ rb_hash_foreach(python_type_mapping, get_mapped_ancestor_class_iter, (VALUE)args);
+
+ return args[1];
+}
+
+static VALUE
pycall_python_type_mapping_get_mapped_class(VALUE pytypeptr)
{
+ VALUE mapped;
(void)check_get_pytypeobj_ptr(pytypeptr);
- return rb_hash_lookup(python_type_mapping, pytypeptr);
+ mapped = rb_hash_lookup(python_type_mapping, pytypeptr);
+ if (NIL_P(mapped)) {
+ mapped = pycall_python_type_mapping_get_mapped_ancestor_class(pytypeptr);
+ }
+ return mapped;
}
static int
pycall_python_type_mapping_register(VALUE pytypeptr, VALUE rbcls)
{
@@ -2177,9 +2219,10 @@
rb_define_method(cPyTypePtr, "__ob_size__", pycall_pytypeptr_get_ob_size, 0);
rb_define_method(cPyTypePtr, "__tp_name__", pycall_pytypeptr_get_tp_name, 0);
rb_define_method(cPyTypePtr, "__tp_basicsize__", pycall_pytypeptr_get_tp_basicsize, 0);
rb_define_method(cPyTypePtr, "__tp_flags__", pycall_pytypeptr_get_tp_flags, 0);
rb_define_method(cPyTypePtr, "===", pycall_pytypeptr_eqq, 1);
+ rb_define_method(cPyTypePtr, "<", pycall_pytypeptr_subclass_p, 1);
/* PyCall::LibPython::API */
mLibPython = rb_define_module_under(mPyCall, "LibPython");
pycall_libpython_handle = rb_funcall(mLibPython, rb_intern("handle"), 0);