Commits

Bob Ippolito committed 9f445fe

Add formal protocol support (not creating, just implementing)
XXX: Classes are not checked against formal implementation
XXX: protocols are checked to be PyObjCObject, not more specific

Comments (0)

Files changed (7)

Modules/objc/class-builder.m

 	int                      ivar_size  = 0;
 	int                      meta_method_count = 0;
 	int                      method_count = 0;
+	int                      protocol_count = 0;
 	int                      first_python_gen = 0;
 	struct objc_ivar_list*   ivar_list = NULL;
 	struct objc_method_list* method_list = NULL;
 	struct objc_method_list* meta_method_list = NULL;
+	struct objc_protocol_list* protocol_list = NULL;
 	struct class_wrapper*    new_class = NULL;
 	Class                    root_class;
 	Class                    cur_class;
 		goto error_cleanup;
 	}
 
-    PyDict_SetItemString(class_dict, "__objc_python_subclass__", Py_True);
+	PyDict_SetItemString(class_dict, "__objc_python_subclass__", Py_True);
 
 	py_superclass = PyObjCClass_New(super_class);
 	if (py_superclass == NULL) return NULL;
 		}
 	}
 
+	protocol_count = PyList_Size(protocols);
+	if (protocol_count > 0) {
+		int cur_protocol = 0;
+		protocol_list = PyObjCRT_AllocProtocolList(protocol_count);
+		if (protocol_list == NULL) {
+			PyErr_NoMemory();
+			goto error_cleanup;
+		}
+		for (i=0; i < protocol_count; i++) {
+			Protocol *protocol;
+			PyObject *wrapped_protocol;
+			wrapped_protocol = PyList_GET_ITEM(protocols, i);
+			if (PyObjCInformalProtocol_Check(wrapped_protocol)) {
+				continue;
+			}
+			if (!PyObjCObject_Check(wrapped_protocol)) {
+				PyErr_Format(PyObjCExc_Error,
+					"protocol must be a PyObjCObject, not an '%s'",
+					wrapped_protocol->ob_type->tp_name);
+				goto error_cleanup;
+			}
+			protocol = (Protocol *)PyObjCObject_GetObject(wrapped_protocol);
+			protocol_list->list[cur_protocol] = protocol;
+			cur_protocol++;
+		}
+		protocol_list->list[cur_protocol] = nil;
+		protocol_list->count = cur_protocol;
+	}
+	
+
 	key_list = PyDict_Keys(class_dict);
 	if (key_list == NULL) {
 		goto error_cleanup;
 		name,
 		super_class,
 		root_class,
-		ivar_size, ivar_list
+		ivar_size, ivar_list,
+		protocol_list
 		);
 	if (i < 0) {
 		goto error_cleanup;
 	if (meta_method_list) {
 		free(meta_method_list);
 	}
+	if (protocol_list) {
+		free(protocol_list);
+	}
 
 	if (new_class != NULL) {
 		PyObjCRT_ClearClass(&(new_class->class));
 		PyObjCRT_ClearClass(&(new_class->meta_class));
-        free(new_class);
+		free(new_class);
 	}
 
 	return NULL;

Modules/objc/objc-class.m

 			return NULL;
 		} else if (PyObjCInformalProtocol_Check(v)) {
 			PyList_Append(protocols, v);
+		} else if (PyObjCObject_Check(v)) {
+			// XXX: Check to see if it is *actually* a Protocol?
+			PyList_Append(protocols, v);
 		} else {
 			PyList_Append(real_bases, v);
 		}

Modules/objc/objc-runtime-apple.h

 
 
 extern struct objc_method_list* PyObjCRT_AllocMethodList(int);
+extern struct objc_protocol_list* PyObjCRT_AllocProtocolList(int);
 
 typedef Method PyObjCRT_Method_t;
 typedef Ivar PyObjCRT_Ivar_t;

Modules/objc/objc-runtime-apple.m

 	Class superCls,
 	Class rootCls,
 	int ivarSize,
-	struct objc_ivar_list* 	ivarList
+	struct objc_ivar_list* ivarList,
+	struct objc_protocol_list* protocolList
 )
 
 {
 	}
 	memset(metaCls->methodLists, 0, sizeof(*(metaCls->methodLists)));
 
-        /*
-         * This is MacOS X specific, and an undocumented feature (long live
-         * Open Source!).
-         *
-         * The code in the objc runtime assumes that the method lists are
-         * terminated by '-1', and will happily overwite existing data if
-         * they aren't.
-         *
-         * Ronald filed a bugreport for this: Radar #3317376
-         */
-        cls->methodLists[0] = (struct objc_method_list*)-1;
-        metaCls->methodLists[0] = (struct objc_method_list*)-1;
+	/*
+	 * This is MacOS X specific, and an undocumented feature (long live
+	 * Open Source!).
+	 *
+	 * The code in the objc runtime assumes that the method lists are
+	 * terminated by '-1', and will happily overwite existing data if
+	 * they aren't.
+	 *
+	 * Ronald filed a bugreport for this: Radar #3317376
+	 */
+	cls->methodLists[0] = (struct objc_method_list*)-1;
+	metaCls->methodLists[0] = (struct objc_method_list*)-1;
 
 	cls->super_class = superCls;
 	metaCls->super_class = superCls->isa;
 	metaCls->instance_size = metaCls->super_class->instance_size;
 	metaCls->ivars = NULL;
 
-	cls->protocols = metaCls->protocols = NULL;
+	metaCls->protocols = cls->protocols = protocolList;
 
 	return 0;
 }
 
 struct objc_method_list *PyObjCRT_AllocMethodList(int numMethods)
 {
-        struct objc_method_list *mlist;
+	struct objc_method_list *mlist;
 
-        mlist = malloc(sizeof(struct objc_method_list)
-                 + ((numMethods+1) * sizeof(struct objc_method)));
+	mlist = malloc(sizeof(struct objc_method_list)
+			 + ((numMethods+1) * sizeof(struct objc_method)));
 
-        if (mlist == NULL) {
-                return NULL;
-        }
+	if (mlist == NULL) {
+			return NULL;
+	}
 
-        mlist->method_count = 0;
-        mlist->obsolete = NULL;
+	mlist->method_count = 0;
+	mlist->obsolete = NULL;
 
-        return mlist;
+	return mlist;
+}
+
+struct objc_protocol_list* PyObjCRT_AllocProtocolList(int numProtocols)
+{
+	struct objc_protocol_list *plist;
+
+	plist = malloc(sizeof(struct objc_protocol_list)
+			 + ((numProtocols+1) * sizeof(Protocol *)));
+
+	if (plist == NULL) {
+			return NULL;
+	}
+
+	plist->count = 0;
+	plist->next = NULL;
+
+	return plist;
 }
 
 #else /* !APPLE_RUNTIME */

Modules/objc/objc-runtime-gnu.h

 
 
 extern MethodList_t PyObjCRT_AllocMethodList(int);
+extern struct objc_protocol_list* PyObjCRT_AllocProtocolList(int);
 
 
 typedef Method_t PyObjCRT_Method_t;

Modules/objc/objc-runtime-gnu.m

 
 #if defined(GNU_RUNTIME)
 
+struct objc_protocol_list* PyObjCRT_AllocProtocolList(int numProtocols)
+{   
+	struct objc_protocol_list *plist;
+	
+	plist = malloc(sizeof(struct objc_protocol_list)
+			 + ((numProtocols+1) * sizeof(Protocol *)));
+
+	if (plist == NULL) {
+			return NULL;
+	}
+	
+	plist->count = 0;
+	plist->next = NULL;
+
+	return plist;
+}
+
 int PyObjCRT_SetupClass(
 	Class cls, 
 	Class metaCls, 
 	Class superCls,
 	Class rootCls,
 	int ivarSize,
-	struct objc_ivar_list* 	ivarList
+	struct objc_ivar_list* 	ivarList,
+	struct objc_protocol_list* protocolList
 )
 
 {
 	metaCls->subclass_list = NULL;
 	cls->sibling_class = NULL;
 	metaCls->sibling_class = NULL;
-	cls->protocols = NULL;
-	metaCls->protocols = NULL;
 
 	cls->methods = NULL;
 	metaCls->methods = NULL;
 	metaCls->instance_size = metaCls->super_class->instance_size;
 	metaCls->ivars = NULL;
 
-	cls->protocols = metaCls->protocols = NULL;
+	metaCls->protocols = cls->protocols = protocolList;
 
 	metaCls->dtable = objc_get_uninstalled_dtable();
 	cls->dtable = objc_get_uninstalled_dtable();

Modules/objc/objc_support.h

 
 
 extern int PyObjCRT_SetupClass(
-	Class, Class, const char*, Class, Class, int, struct objc_ivar_list*);
+	Class, Class, const char*, Class, Class, int, struct objc_ivar_list*,
+	struct objc_protocol_list*);
 extern void PyObjCRT_ClearClass(Class cls);
 
 #endif /* _objc_support_H */