1/* 2 * Implementation of support type for formal protocols. 3 * 4 * See the module DOCSTR for more information. 5 * 6 * XXX: 7 * - deal with optional methods (new in ObjC 2.0) 8 * - creating new protocols isn't actually supported in ObjC 2.0 9 */ 10#include "pyobjc.h" 11 12/* 13 * FIXME: Looking in the Protocol structure is a rather crude hack, especially with the Objective-C 2.0 14 * runtime API. Too bad there is no real API for doing what we want... 15 */ 16struct Protocol_struct { 17#ifndef __OBJC2__ 18 @defs(Protocol); 19#else 20 char *protocol_name; 21 struct objc_protocol_list *protocol_list; 22 struct objc_method_description_list *instance_methods, *class_methods; 23#endif 24}; 25 26PyDoc_STRVAR(proto_cls_doc, 27"objc.formal_protocol(name, supers, selector_list)\n" 28"\n" 29"This class is used to proxy Objective-C formal protocols, and can also be \n" 30"used to define new formal protocols.\n" 31""); 32 33typedef struct { 34 PyObject_HEAD 35 36 Protocol* objc; 37} PyObjCFormalProtocol; 38 39 40static void 41proto_dealloc(PyObject* object) 42{ 43 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 44 PyObjC_UnregisterPythonProxy(self->objc, object); 45 object->ob_type->tp_free(object); 46} 47 48 49static PyObject* 50proto_repr(PyObject* object) 51{ 52 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 53 const char* name; 54 55 name = protocol_getName(self->objc); 56 if (name == NULL) { 57 name = "<nil>"; 58 } 59 60 return PyString_FromFormat("<%s %s at %p>", self->ob_type->tp_name, name, (void*)self); 61} 62 63static PyObject* 64proto_get__class__(PyObject* object __attribute__((__unused__)), void* closure __attribute__((__unused__))) 65{ 66 return PyObjCClass_New([Protocol class]); 67} 68 69static PyObject* 70proto_get__name__(PyObject* object, void* closure __attribute__((__unused__))) 71{ 72 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 73 const char* name = protocol_getName(self->objc); 74 75 if (name == NULL) { 76 Py_INCREF(Py_None); 77 return Py_None; 78 } 79 80 return PyString_FromString(name); 81} 82 83 84static PyObject* 85proto_new(PyTypeObject* type __attribute__((__unused__)), 86 PyObject* args, PyObject* kwds) 87{ 88static char* keywords[] = { "name", "supers", "selectors", NULL }; 89 char* name; 90 PyObject* supers; 91 PyObject* selectors; 92 Py_ssize_t i, len; 93 94#ifndef __LP64__ 95 PyObjCFormalProtocol* result = NULL; 96 Py_ssize_t numInstance = 0; 97 Py_ssize_t numClass = 0; 98 struct Protocol_struct* theProtocol = NULL; 99 struct objc_method_description* c; 100#endif 101 102 if (!PyArg_ParseTupleAndKeywords(args, kwds, "sOO:formal_protocol", 103 keywords, &name, &supers, &selectors)) { 104 return NULL; 105 } 106 107 if (supers != Py_None) { 108 supers = PySequence_Fast(supers, "supers need to be a sequence of objc.formal_protocols"); 109 if (supers == NULL) return NULL; 110 len = PySequence_Fast_GET_SIZE(supers); 111 for (i = 0; i < len; i++) { 112 PyObject* v = PySequence_Fast_GET_ITEM(supers, i); 113 if (!PyObjCFormalProtocol_Check(v)) { 114 PyErr_SetString(PyExc_TypeError, "supers need to be a sequence of objc.formal_protocols"); 115 Py_DECREF(supers); 116 return NULL; 117 } 118 } 119 120 } else { 121 Py_INCREF(supers); 122 } 123 124 selectors = PySequence_Fast(selectors, "selectors need to be a sequence of selectors"); 125 if (selectors == NULL) { 126 Py_DECREF(supers); 127 return NULL; 128 } 129 130#ifdef __LP64__ 131 /* Radar #5272299: the objective-C 2.0 runtime API doesn't have an interface for constructing new 132 * formal protocols. We can kind-of fake this for now in 32-bit mode, but that won't work in 64-bit 133 * mode due to additional flexibility in that mode (which in itself is a good thing). 134 */ 135 Py_DECREF(selectors); 136 PyErr_SetString(PyObjCExc_Error, "The Objective-C 2.0 runtime API doesn't allow creation of formal protocols"); 137 return NULL; 138 139#else 140 /* 141 * The code below isn't actually supported on the ObjC 2.0 runtime, but happens to work 142 * in 32-bit mode. Radar #5272299 asks for a formal API to do this. 143 */ 144 145 146 len = PySequence_Fast_GET_SIZE(selectors); 147 for (i = 0; i < len; i++) { 148 PyObject* sel = PySequence_Fast_GET_ITEM(selectors, i); 149 if (sel == NULL || !PyObjCSelector_Check(sel)) { 150 PyErr_SetString(PyExc_TypeError, 151 "selectors need to be a sequence of selectors"); 152 Py_DECREF(supers); 153 Py_DECREF(selectors); 154 return NULL; 155 } 156 if (PyObjCSelector_GetFlags(sel)&PyObjCSelector_kCLASS_METHOD) { 157 numClass++; 158 } else { 159 numInstance++; 160 } 161 } 162 163 theProtocol = (struct Protocol_struct*)NSAllocateObject([Protocol class], 0, NULL); 164 if (theProtocol == NULL) { 165 PyErr_NoMemory(); 166 goto error; 167 } 168 169 170 theProtocol->protocol_name = strdup(name); 171 if (theProtocol->protocol_name == NULL) { 172 PyErr_NoMemory(); 173 goto error; 174 } 175 176 if (supers == Py_None) { 177 theProtocol->protocol_list = NULL; 178 } else { 179 len = PySequence_Fast_GET_SIZE(supers); 180 theProtocol->protocol_list = malloc( 181 sizeof(struct objc_protocol_list) + 182 (1+len) * sizeof(Protocol*)); 183 theProtocol->protocol_list->next = NULL; 184 theProtocol->protocol_list->count = len; 185 for (i = 0; i < len; i++) { 186 PyObject* v = PySequence_Fast_GET_ITEM(supers, i); 187 theProtocol->protocol_list->list[i] = 188 PyObjCFormalProtocol_GetProtocol(v); 189 if (theProtocol->protocol_list->list[i] == NULL) { 190 goto error; 191 } 192 } 193 theProtocol->protocol_list->list[i] = NULL; 194 } 195 196 if (numInstance != 0) { 197 theProtocol->instance_methods = malloc( 198 sizeof(struct objc_method_description_list) + 199 (1+numInstance) * sizeof(struct objc_method_description)); 200 if (theProtocol->instance_methods == NULL) { 201 PyErr_NoMemory(); 202 goto error; 203 } 204 theProtocol->instance_methods->count = 0; 205 } 206 if (numClass != 0) { 207 theProtocol->class_methods = malloc( 208 sizeof(struct objc_method_description_list) + 209 (1+numClass) * sizeof(struct objc_method_description)); 210 if (theProtocol->class_methods == NULL) { 211 PyErr_NoMemory(); 212 goto error; 213 } 214 theProtocol->class_methods->count = 0; 215 } 216 217 len = PySequence_Fast_GET_SIZE(selectors); 218 for (i = 0; i < len; i++) { 219 PyObject* sel = PySequence_Fast_GET_ITEM(selectors, i); 220 SEL theSel = PyObjCSelector_GetSelector(sel); 221 char* theSignature = PyObjCSelector_Signature(sel); 222 223 if (PyObjCSelector_GetFlags(sel)&PyObjCSelector_kCLASS_METHOD) { 224 c = &(theProtocol->class_methods->list[ 225 theProtocol->class_methods->count++]); 226 c->name = theSel; 227 c->types = strdup(theSignature); 228 if (c->types == NULL) goto error; 229 } else { 230 c = &(theProtocol->instance_methods->list[ 231 theProtocol->instance_methods->count++]); 232 c->name = theSel; 233 c->types = strdup(theSignature); 234 if (c->types == NULL) goto error; 235 } 236 } 237 238 if (theProtocol->instance_methods) { 239 c = &(theProtocol->instance_methods->list[ 240 theProtocol->instance_methods->count]); 241 c->name = NULL; 242 c->types = NULL; 243 } 244 245 if (theProtocol->class_methods) { 246 c = &(theProtocol->class_methods->list[ 247 theProtocol->class_methods->count]); 248 c->name = NULL; 249 c->types = NULL; 250 } 251 252 253 result = (PyObjCFormalProtocol*)PyObject_New( 254 PyObjCFormalProtocol, &PyObjCFormalProtocol_Type); 255 if (result == NULL) goto error; 256 257 Py_DECREF(selectors); 258 Py_DECREF(supers); 259 260 result->objc = (Protocol*)theProtocol; 261 PyObjC_RegisterPythonProxy(result->objc, (PyObject*)result); 262 return (PyObject*)result; 263 264error: 265 Py_DECREF(selectors); 266 Py_DECREF(supers); 267 268 if (theProtocol == NULL) return NULL; 269 270 if (theProtocol->protocol_name != NULL) { 271 free(theProtocol->protocol_name); 272 } 273 274 if (theProtocol->protocol_list != NULL) { 275 free(theProtocol->protocol_list); 276 } 277 278 if (theProtocol->instance_methods != NULL) { 279 for (i = 0; i < theProtocol->instance_methods->count; i++) { 280 c = theProtocol->instance_methods->list + i; 281 if (c->name) { 282 free(c->name); 283 } 284 } 285 free(theProtocol->instance_methods); 286 } 287 288 if (theProtocol->class_methods != NULL) { 289 for (i = 0; i < theProtocol->class_methods->count; i++) { 290 c = theProtocol->class_methods->list + i; 291 if (c->name) { 292 free(c->name); 293 } 294 } 295 free(theProtocol->class_methods); 296 } 297 return NULL; 298 299#endif /* !__LP64__ */ 300} 301 302static PyObject* 303proto_name(PyObject* object) 304{ 305 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 306 const char* name = protocol_getName(self->objc); 307 308 if (name == NULL) { 309 Py_INCREF(Py_None); 310 return Py_None; 311 } 312 313 return PyString_FromString(name); 314} 315 316static PyObject* 317proto_conformsTo_(PyObject* object, PyObject* args) 318{ 319 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 320 PyObject* protocol; 321 Protocol* objc_protocol; 322 323 if (!PyArg_ParseTuple(args, "O", &protocol)) { 324 return NULL; 325 } 326 327 if (!PyObjCFormalProtocol_Check(protocol)) { 328 PyErr_SetString(PyExc_TypeError, "Expecting a formal protocol"); 329 return NULL; 330 } 331 objc_protocol = PyObjCFormalProtocol_GetProtocol(protocol); 332 333 if (protocol_conformsToProtocol(self->objc, objc_protocol)) { 334 return PyBool_FromLong(1); 335 } else { 336 return PyBool_FromLong(0); 337 } 338} 339 340static PyObject* 341descriptionForInstanceMethod_(PyObject* object, PyObject* sel) 342{ 343 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 344 SEL aSelector = NULL; 345 struct objc_method_description descr; 346 347 if (PyObjCSelector_Check(sel)) { 348 aSelector = PyObjCSelector_GetSelector(sel); 349 } else if (PyString_Check(sel)) { 350 char* s = PyString_AsString(sel); 351 if (*s == '\0') { 352 PyErr_SetString(PyExc_ValueError, 353 "empty selector name"); 354 return NULL; 355 } 356 357 aSelector = sel_getUid(s); 358 } else { 359 PyErr_Format(PyExc_TypeError, "expecting a SEL, got instance of %s", 360 sel->ob_type->tp_name); 361 return NULL; 362 } 363 364 descr = protocol_getMethodDescription(self->objc, aSelector, YES, YES); 365 if (descr.name == NULL) { 366 descr = protocol_getMethodDescription(self->objc, aSelector, NO, YES); 367 } 368 369 if (descr.name == NULL) { 370 Py_INCREF(Py_None); 371 return Py_None; 372 373 } else { 374 return Py_BuildValue("(ss)", 375 sel_getName(descr.name), 376 descr.types); 377 } 378} 379 380static PyObject* 381descriptionForClassMethod_(PyObject* object, PyObject* sel) 382{ 383 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 384 SEL aSelector = NULL; 385 struct objc_method_description descr; 386 387 if (PyObjCSelector_Check(sel)) { 388 aSelector = PyObjCSelector_GetSelector(sel); 389 } else if (PyString_Check(sel)) { 390 char* s = PyString_AsString(sel); 391 if (*s == '\0') { 392 PyErr_SetString(PyExc_ValueError, 393 "empty selector name"); 394 return NULL; 395 } 396 397 aSelector = sel_getUid(s); 398 } 399 400 descr = protocol_getMethodDescription(self->objc, aSelector, YES, NO); 401 if (descr.name == NULL) { 402 descr = protocol_getMethodDescription(self->objc, aSelector, NO, NO); 403 } 404 if (descr.name == NULL) { 405 Py_INCREF(Py_None); 406 return Py_None; 407 } else { 408 return Py_BuildValue("(ss)", 409 sel_getName(descr.name), 410 descr.types); 411 } 412} 413 414static PyMethodDef proto_methods[] = { 415 { 416 "name", 417 (PyCFunction)proto_name, 418 METH_NOARGS, 419 "Return the protocol name", 420 }, 421 { 422 "conformsTo_", 423 (PyCFunction)proto_conformsTo_, 424 METH_VARARGS, 425 "Does this protocol conform to another protocol" 426 }, 427 { 428 "descriptionForInstanceMethod_", 429 (PyCFunction)descriptionForInstanceMethod_, 430 METH_O, 431 "Description for an instance method in the protocol" 432 }, 433 { 434 "descriptionForClassMethod_", 435 (PyCFunction)descriptionForClassMethod_, 436 METH_O, 437 "Description for a class method in the protocol" 438 }, 439 { 0, 0, 0, 0 } 440}; 441 442static PyGetSetDef proto_getset[] = { 443 { 444 "__class__", 445 (getter)proto_get__class__, 446 NULL, 447 NULL, 448 0 449 }, 450 { 451 "__name__", 452 (getter)proto_get__name__, 453 NULL, 454 NULL, 455 0 456 }, 457 { NULL, NULL, NULL, NULL, 0 } 458}; 459 460PyTypeObject PyObjCFormalProtocol_Type = { 461 PyObject_HEAD_INIT(&PyType_Type) 462 0, /* ob_size */ 463 "objc.formal_protocol", /* tp_name */ 464 sizeof(PyObjCFormalProtocol), /* tp_basicsize */ 465 0, /* tp_itemsize */ 466 /* methods */ 467 proto_dealloc, /* tp_dealloc */ 468 0, /* tp_print */ 469 0, /* tp_getattr */ 470 0, /* tp_setattr */ 471 0, /* tp_compare */ 472 proto_repr, /* tp_repr */ 473 0, /* tp_as_number */ 474 0, /* tp_as_sequence */ 475 0, /* tp_as_mapping */ 476 0, /* tp_hash */ 477 0, /* tp_call */ 478 0, /* tp_str */ 479 PyObject_GenericGetAttr, /* tp_getattro */ 480 0, /* tp_setattro */ 481 0, /* tp_as_buffer */ 482 Py_TPFLAGS_DEFAULT, /* tp_flags */ 483 proto_cls_doc, /* tp_doc */ 484 0, /* tp_traverse */ 485 0, /* tp_clear */ 486 0, /* tp_richcompare */ 487 0, /* tp_weaklistoffset */ 488 0, /* tp_iter */ 489 0, /* tp_iternext */ 490 proto_methods, /* tp_methods */ 491 0, /* tp_members */ 492 proto_getset, /* tp_getset */ 493 0, /* tp_base */ 494 0, /* tp_dict */ 495 0, /* tp_descr_get */ 496 0, /* tp_descr_set */ 497 0, /* tp_dictoffset */ 498 0, /* tp_init */ 499 0, /* tp_alloc */ 500 proto_new, /* tp_new */ 501 0, /* tp_free */ 502 0, /* tp_is_gc */ 503 0, /* tp_bases */ 504 0, /* tp_mro */ 505 0, /* tp_cache */ 506 0, /* tp_subclasses */ 507 0, /* tp_weaklist */ 508 0 /* tp_del */ 509#if PY_VERSION_HEX >= 0x02060000 510 , 0 /* tp_version_tag */ 511#endif 512 513}; 514 515 516/* 517 * Find information about a selector in the protocol. 518 * 519 * Return NULL if no information can be found, but does not set an 520 * exception. 521 */ 522const char* 523PyObjCFormalProtocol_FindSelectorSignature(PyObject* object, SEL selector, int isClassMethod) 524{ 525 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 526 struct objc_method_description descr; 527 528 descr = protocol_getMethodDescription(self->objc, selector, YES, !isClassMethod); 529 if (descr.name != NULL) { 530 return descr.types; 531 } 532 descr = protocol_getMethodDescription(self->objc, selector, NO, !isClassMethod); 533 if (descr.name != NULL) { 534 return descr.types; 535 } 536 return NULL; 537} 538 539static int 540do_verify( 541 const char* protocol_name, 542 struct objc_method_description* descr, 543 BOOL is_class, 544 BOOL is_required, 545 char* name, 546 PyObject* super_class, 547 PyObject* clsdict, PyObject* metadict) 548{ 549 PyObject* meth; 550 551 if (is_class) { 552 meth = findSelInDict(metadict, descr->name); 553 } else { 554 meth = findSelInDict(clsdict, descr->name); 555 } 556 if (meth == NULL || !PyObjCSelector_Check(meth)) { 557 558 meth = PyObjCClass_FindSelector(super_class, descr->name, is_class); 559 if (meth == NULL || !PyObjCSelector_Check(meth)) { 560 if (is_required) { 561 PyErr_Format(PyExc_TypeError, 562 "class %s does not full implement protocol " 563 "%s: no implementation for %s", 564 name, 565 protocol_name, 566 sel_getName(descr->name)); 567 return 0; 568 } else { 569 /* Method is not required, ignore */ 570 return 1; 571 } 572 } 573 } 574 575 if (is_class) { 576 if (!PyObjCSelector_IsClassMethod(meth)) { 577 PyErr_Format(PyExc_TypeError, 578 "class %s does not correctly implement " 579 "protocol %s: method %s is not a " 580 "class method", 581 name, 582 protocol_name, 583 sel_getName(descr->name) 584 ); 585 return 0; 586 } 587 } else { 588 if (PyObjCSelector_IsClassMethod(meth)) { 589 PyErr_Format(PyExc_TypeError, 590 "class %s does not correctly implement " 591 "protocol %s: method %s is not an " 592 "instance method", 593 name, 594 protocol_name, 595 sel_getName(descr->name) 596 ); 597 return 0; 598 } 599 } 600 601 if (signaturesEqual(descr->types, 602 PyObjCSelector_Signature(meth))) { 603 return 1; 604 } 605 606 PyErr_Format(PyExc_TypeError, 607 "class %s does not correctly implement " 608 "protocol %s: the signature for method %s " 609 "is %s instead of %s", 610 name, 611 protocol_name, 612 sel_getName(descr->name), 613 PyObjCSelector_Signature(meth), 614 descr->types); 615 return 0; 616} 617 618static int 619do_check( 620 const char* protocol_name, 621 Protocol* protocol, 622 char* name, 623 PyObject* super_class, 624 PyObject* clsdict, 625 PyObject* metadict) 626{ 627 int r; 628 unsigned idx; 629 630 unsigned parentCount; 631 Protocol** parents = protocol_copyProtocolList(protocol, &parentCount); 632 if (parents) { 633 for (idx = 0; idx < parentCount; idx++) { 634 r = do_check(protocol_name, parents[idx], name, super_class, clsdict, metadict); 635 if (r == 0) { 636 free(parents); 637 return r; 638 } 639 } 640 free(parents); 641 } 642 643 unsigned int methCount; 644 struct objc_method_description* methinfo; 645 646 methCount = 0; 647 methinfo = protocol_copyMethodDescriptionList(protocol, YES, YES, &methCount); 648 if (methinfo) { 649 for (idx = 0; idx < methCount; idx++) { 650 if (!do_verify(protocol_name, methinfo + idx, NO, YES, name, super_class, clsdict, metadict)) { 651 free(methinfo); 652 return 0; 653 } 654 } 655 free(methinfo); 656 } 657 658 methinfo = protocol_copyMethodDescriptionList(protocol, NO, YES, &methCount); 659 if (methinfo) { 660 for (idx = 0; idx < methCount; idx++) { 661 if (!do_verify(protocol_name, methinfo + idx, NO, NO, name, super_class, clsdict, metadict)) { 662 free(methinfo); 663 return 0; 664 } 665 } 666 free(methinfo); 667 } 668 669 methinfo = protocol_copyMethodDescriptionList(protocol, YES, NO, &methCount); 670 if (methinfo) { 671 for (idx = 0; idx < methCount; idx++) { 672 if (!do_verify(protocol_name, methinfo + idx, YES, YES, name, super_class, clsdict, metadict)) { 673 free(methinfo); 674 return 0; 675 } 676 } 677 free(methinfo); 678 } 679 680 methinfo = protocol_copyMethodDescriptionList(protocol, NO, NO, &methCount); 681 if (methinfo) { 682 for (idx = 0; idx < methCount; idx++) { 683 if (!do_verify(protocol_name, methinfo + idx, YES, NO, name, super_class, clsdict, metadict)) { 684 free(methinfo); 685 return 0; 686 } 687 } 688 free(methinfo); 689 } 690 691 return 1; 692} 693 694int 695PyObjCFormalProtocol_CheckClass( 696 PyObject* obj, char* name, PyObject* super_class, PyObject* clsdict, PyObject* metadict) 697{ 698 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)obj; 699 700 if (!PyObjCFormalProtocol_Check(obj)) { 701 PyErr_Format(PyExc_TypeError, 702 "First argument is not an 'objc.formal_protocol' but " 703 "'%s'", obj->ob_type->tp_name); 704 return 0; 705 } 706 if (!PyObjCClass_Check(super_class)) { 707 PyErr_Format(PyExc_TypeError, 708 "Third argument is not an 'objc.objc_class' but " 709 "'%s'", super_class->ob_type->tp_name); 710 return 0; 711 } 712 if (!PyDict_Check(clsdict)) { 713 PyErr_Format(PyExc_TypeError, 714 "Fourth argument is not a 'dict' but '%s'", 715 clsdict->ob_type->tp_name); 716 return 0; 717 } 718 719 return do_check(protocol_getName(self->objc), self->objc, name, super_class, clsdict, metadict); 720} 721 722PyObject* PyObjCFormalProtocol_ForProtocol(Protocol* protocol) 723{ 724 PyObjCFormalProtocol* result; 725 726 result = (PyObjCFormalProtocol*)PyObject_New( 727 PyObjCFormalProtocol, &PyObjCFormalProtocol_Type); 728 if (result == NULL) { 729 return NULL; 730 } 731 732 result->objc = protocol; 733 PyObjC_RegisterPythonProxy(result->objc, (PyObject*)result); 734 return (PyObject*)result; 735} 736 737Protocol* PyObjCFormalProtocol_GetProtocol(PyObject* object) 738{ 739 PyObjCFormalProtocol* self = (PyObjCFormalProtocol*)object; 740 741 if (!PyObjCFormalProtocol_Check(self)) { 742 PyErr_Format(PyExc_TypeError, 743 "Expecting objc.formal_protocol, got %s", 744 self->ob_type->tp_name); 745 return NULL; 746 } 747 748 return self->objc; 749} 750