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