| 1181 | } |
| 1182 | |
| 1183 | PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs) { |
| 1184 | static const char *const _keywords[] = {"key", "reverse", NULL}; |
| 1185 | |
| 1186 | PyObject *keyfunc = Py_None; |
| 1187 | int reverse = 0; |
| 1188 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$Op:sort", (char **)_keywords, &keyfunc, &reverse)) { |
| 1189 | return NULL; |
| 1190 | } |
| 1191 | |
| 1192 | if (JSArrayProxy_length(self) > 1) { |
| 1193 | JS::RootedValue jReturnedArray(GLOBAL_CX); |
| 1194 | if (keyfunc != Py_None) { |
| 1195 | if (PyFunction_Check(keyfunc)) { |
| 1196 | // we got a python key function, check if two-argument js style or standard python 1-arg |
| 1197 | PyObject *code = PyFunction_GetCode(keyfunc); |
| 1198 | if (((PyCodeObject *)code)->co_argcount == 1) { |
| 1199 | // adapt to python style, provide js-style comp wrapper that does it the python way, which is < based with calls to keyFunc |
| 1200 | JS::RootedObject funObj(GLOBAL_CX, JS_GetFunctionObject(JS_NewFunction(GLOBAL_CX, sort_compare_key_func, 2, 0, NULL))); |
| 1201 | |
| 1202 | JS::RootedValue privateValue(GLOBAL_CX, JS::PrivateValue(keyfunc)); |
| 1203 | if (!JS_SetProperty(GLOBAL_CX, funObj, "_key_func_param", privateValue)) { // JS::SetReservedSlot(functionObj, KeyFuncSlot, JS::PrivateValue(keyfunc)); does not work |
| 1204 | PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSArrayProxyType.tp_name); |
| 1205 | return NULL; |
| 1206 | } |
| 1207 | |
| 1208 | JS::RootedValue reverseValue(GLOBAL_CX); |
| 1209 | reverseValue.setBoolean(reverse); |
| 1210 | if (!JS_SetProperty(GLOBAL_CX, funObj, "_reverse_param", reverseValue)) { |
| 1211 | PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSArrayProxyType.tp_name); |
| 1212 | return NULL; |
| 1213 | } |
| 1214 | |
| 1215 | JS::Rooted<JS::ValueArray<1>> jArgs(GLOBAL_CX); |
| 1216 | jArgs[0].setObject(*funObj); |
| 1217 | if (!JS_CallFunctionName(GLOBAL_CX, *(self->jsArray), "sort", jArgs, &jReturnedArray)) { |
| 1218 | if (!PyErr_Occurred()) { |
| 1219 | PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSArrayProxyType.tp_name); |
| 1220 | } |
| 1221 | return NULL; |
| 1222 | } |
| 1223 | |
| 1224 | // cleanup |
| 1225 | if (!JS_DeleteProperty(GLOBAL_CX, funObj, "_key_func_param")) { |
| 1226 | PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSArrayProxyType.tp_name); |
| 1227 | return NULL; |
| 1228 | } |
| 1229 | |
| 1230 | if (!JS_DeleteProperty(GLOBAL_CX, funObj, "_reverse_param")) { |
| 1231 | PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSArrayProxyType.tp_name); |
| 1232 | return NULL; |
| 1233 | } |
| 1234 | } |
| 1235 | else { |
| 1236 | // two-arg js-style |
| 1237 | JS::Rooted<JS::ValueArray<1>> jArgs(GLOBAL_CX); |
| 1238 | jArgs[0].set(jsTypeFactory(GLOBAL_CX, keyfunc)); |
| 1239 | if (!JS_CallFunctionName(GLOBAL_CX, *(self->jsArray), "sort", jArgs, &jReturnedArray)) { |
| 1240 | PyErr_Format(PyExc_SystemError, "%s JSAPI call failed", JSArrayProxyType.tp_name); |
nothing calls this directly
no test coverage detected