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);