support for multiple return values from rna functions & support for returning arrays...
authorCampbell Barton <ideasman42@gmail.com>
Sat, 2 Jan 2010 10:42:38 +0000 (10:42 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 2 Jan 2010 10:42:38 +0000 (10:42 +0000)
patch from Elia Sarti, (vekoon) with some modifications mainly for the python api.

- multiple values are returned as a typle in the order that are defined.
- added support for registered types returning multiple arguments (untested).
- renamed func->ret --> func->c_ret, since this only defines what the C function returns.

source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_define.h
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_define.c
source/blender/makesrna/intern/rna_internal_types.h
source/blender/python/intern/bpy_rna.c

index 39232113581a80f13e7b9631cf3c3532b86963ac..e631e037e744ac2846d9a08038a0219788bb9cc9 100644 (file)
@@ -854,7 +854,6 @@ char *RNA_pointer_as_string(PointerRNA *ptr);
 /* Function */
 
 const char *RNA_function_identifier(FunctionRNA *func);
-PropertyRNA *RNA_function_return(FunctionRNA *func);
 const char *RNA_function_ui_description(FunctionRNA *func);
 int RNA_function_flag(FunctionRNA *func);
 int RNA_function_defined(FunctionRNA *func);
index 37abe44f128a8f16fce67e79239283609b56d9c2..f340834d93b0e9632ff8f01bf89bd330bc82a7a0 100644 (file)
@@ -172,6 +172,7 @@ void RNA_def_property_srna(PropertyRNA *prop, const char *type);
 FunctionRNA *RNA_def_function(StructRNA *srna, const char *identifier, const char *call);
 FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, CallFunc call);
 void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret);
+void RNA_def_function_return_mark(FunctionRNA *func, PropertyRNA *ret);
 void RNA_def_function_flag(FunctionRNA *func, int flag);
 void RNA_def_function_ui_description(FunctionRNA *func, const char *description);
 
index 5bdfe228e89afecd09175ef8c6ea4ae8e67ad08b..ca14acb406021f96ec4c490391a1fb8e1473b5ab 100644 (file)
@@ -1236,16 +1236,18 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
        for(; dparm; dparm= dparm->next) {
                if(dparm->prop->arraydimension)
                        ptrstr= "*";
-               else if(dparm->prop==func->ret)
+               else if(dparm->prop==func->c_ret)
                        ptrstr= ((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag & PROP_RNAPTR))? "*": "";
+               else if ((dparm->prop->flag & PROP_RETURN))
+                       ptrstr= ((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag & PROP_RNAPTR))? "**": "*";
                else
                        ptrstr= (dparm->prop->type == PROP_POINTER)? "*": "";
-                        
+
                fprintf(f, "\t%s%s %s%s;\n", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), ptrstr, dparm->prop->identifier);
        }
 
        fprintf(f, "\tchar *_data");
-       if(func->ret) fprintf(f, ", *_retdata");
+       if(func->c_ret) fprintf(f, ", *_retdata");
        fprintf(f, ";\n");
        fprintf(f, "\t\n");
 
@@ -1259,7 +1261,12 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
 
        dparm= dfunc->cont.properties.first;
        for(; dparm; dparm= dparm->next) {
-               if(dparm->prop==func->ret) 
+               if ((dparm->prop->flag & PROP_RETURN))
+                       ptrstr= "";
+               else
+                       ptrstr= "*";
+
+               if(dparm->prop==func->c_ret)
                        fprintf(f, "\t_retdata= _data;\n");
                else if(dparm->prop->arraydimension)
                        fprintf(f, "\t%s= ((%s%s*)_data);\n", dparm->prop->identifier, rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
@@ -1267,10 +1274,10 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
                        if(dparm->prop->flag & PROP_RNAPTR)
                                fprintf(f, "\t%s= ((%s%s*)_data);\n", dparm->prop->identifier, rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
                        else
-                               fprintf(f, "\t%s= *((%s%s**)_data);\n", dparm->prop->identifier, rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
+                               fprintf(f, "\t%s= %s((%s%s**)_data);\n", dparm->prop->identifier, ptrstr, rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
                }
                else
-                       fprintf(f, "\t%s= *((%s%s*)_data);\n", dparm->prop->identifier, rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
+                       fprintf(f, "\t%s= %s((%s%s*)_data);\n", dparm->prop->identifier, ptrstr, rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
 
                if(dparm->next)
                        fprintf(f, "\t_data+= %d;\n", rna_parameter_size(dparm->prop));
@@ -1279,7 +1286,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
        if(dfunc->call) {
                fprintf(f, "\t\n");
                fprintf(f, "\t");
-               if(func->ret) fprintf(f, "%s= ", func->ret->identifier);
+               if(func->c_ret) fprintf(f, "%s= ", func->c_ret->identifier);
                fprintf(f, "%s(", dfunc->call);
 
                first= 1;
@@ -1303,7 +1310,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
 
                dparm= dfunc->cont.properties.first;
                for(; dparm; dparm= dparm->next) {
-                       if(dparm->prop==func->ret)
+                       if(dparm->prop==func->c_ret)
                                continue;
 
                        if(!first) fprintf(f, ", ");
@@ -1314,10 +1321,10 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
 
                fprintf(f, ");\n");
 
-               if(func->ret) {
-                       dparm= rna_find_parameter_def(func->ret);
+               if(func->c_ret) {
+                       dparm= rna_find_parameter_def(func->c_ret);
                        ptrstr= (((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag & PROP_RNAPTR)) || (dparm->prop->arraydimension))? "*": "";
-                       fprintf(f, "\t*((%s%s%s*)_retdata)= %s;\n", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), ptrstr, func->ret->identifier);
+                       fprintf(f, "\t*((%s%s%s*)_retdata)= %s;\n", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), ptrstr, func->c_ret->identifier);
                }
        }
 
@@ -1552,13 +1559,14 @@ static void rna_generate_static_parameter_prototypes(BlenderRNA *brna, StructRNA
        PropertyDefRNA *dparm;
        StructDefRNA *dsrna;
        int first;
+       char *ptrstr;
 
        dsrna= rna_find_struct_def(srna);
        func= dfunc->func;
 
        /* return type */
        for(dparm= dfunc->cont.properties.first; dparm; dparm= dparm->next) {
-               if(dparm->prop==func->ret) {
+               if(dparm->prop==func->c_ret) {
                        if(dparm->prop->arraydimension)
                                fprintf(f, "XXX no array return types yet"); /* XXX not supported */
                        else if(dparm->prop->type == PROP_POINTER && !(dparm->prop->flag & PROP_RNAPTR))
@@ -1600,18 +1608,23 @@ static void rna_generate_static_parameter_prototypes(BlenderRNA *brna, StructRNA
 
        /* defined parameters */
        for(dparm= dfunc->cont.properties.first; dparm; dparm= dparm->next) {
-               if(dparm->prop==func->ret)
+               if(dparm->prop==func->c_ret)
                        continue;
 
                if(!first) fprintf(f, ", ");
                first= 0;
 
+               if((dparm->prop->flag & PROP_RETURN))
+                       ptrstr= "*";
+               else
+                       ptrstr= "";
+
                if(dparm->prop->arraydimension)
                        fprintf(f, "%s%s %s[%d]", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), dparm->prop->identifier, dparm->prop->totarraylength);
                else if(dparm->prop->type == PROP_POINTER)
-                       fprintf(f, "%s%s *%s", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), dparm->prop->identifier);
+                       fprintf(f, "%s%s *%s%s", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), (dparm->prop->flag & PROP_RNAPTR) ? "" : ptrstr, dparm->prop->identifier);
                else
-                       fprintf(f, "%s%s %s", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), dparm->prop->identifier);
+                       fprintf(f, "%s%s %s%s", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), ptrstr, dparm->prop->identifier);
        }
 
        fprintf(f, ");\n");
@@ -1890,8 +1903,8 @@ static void rna_generate_struct(BlenderRNA *brna, StructRNA *srna, FILE *f)
                dfunc= rna_find_function_def(func);
                if(dfunc->gencall) fprintf(f, "\t%s,\n", dfunc->gencall);
                else fprintf(f, "\tNULL,\n");
-       
-               if(func->ret) fprintf(f, "\t(PropertyRNA*)&rna_%s_%s_%s\n", srna->identifier, func->identifier, func->ret->identifier);
+
+               if(func->c_ret) fprintf(f, "\t(PropertyRNA*)&rna_%s_%s_%s\n", srna->identifier, func->identifier, func->c_ret->identifier);
                else fprintf(f, "\tNULL\n");
 
                fprintf(f, "};\n");
index 7dcc72e41584bcc50df09e6e233cb7762d874fcd..d8b31f4093ec6abe099cc049d81825b5625be4e9 100644 (file)
@@ -3464,11 +3464,6 @@ const char *RNA_function_identifier(FunctionRNA *func)
        return func->identifier;
 }
 
-PropertyRNA *RNA_function_return(FunctionRNA *func)
-{
-       return func->ret;
-}
-
 const char *RNA_function_ui_description(FunctionRNA *func)
 {
        return func->description;
@@ -3929,7 +3924,7 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt
 
        tid= RNA_struct_identifier(ptr->type);
        fid= RNA_function_identifier(func);
-       pret= RNA_function_return(func);
+       pret= func->c_ret;
        flen= strlen(format);
 
        RNA_parameter_list_create(&parms, ptr, func);
@@ -3937,14 +3932,17 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt
 
        for(i= 0, ofs= 0; iter.valid; RNA_parameter_list_next(&iter), i++) {
                parm= iter.parm;
+               flag= RNA_property_flag(parm);
 
                if(parm==pret) {
                        retdata= iter.data;
                        continue;
                }
+               else if (flag & PROP_RETURN) {
+                       continue;
+               }
 
                pid= RNA_property_identifier(parm);
-               flag= RNA_property_flag(parm);
 
                if (ofs>=flen || format[ofs]=='N') {
                        if (flag & PROP_REQUIRED) {
index 9bf5afdac4800f95a419767e52d0dfd3d2b93563..854776e87422c3eabedf6215c5801b5437863147 100644 (file)
@@ -2417,9 +2417,16 @@ FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, C
        return func;
 }
 
+/* C return value only!, multiple rna returns can be done with RNA_def_function_return_mark */
 void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret)
 {
-       func->ret= ret;
+       func->c_ret= ret;
+
+       RNA_def_function_return_mark(func, ret);
+}
+
+void RNA_def_function_return_mark(FunctionRNA *func, PropertyRNA *ret)
+{
        ret->flag|=PROP_RETURN;
 }
 
index 4f05e6132f718f322a9659e296f3422d8cd2bc31..bef568bfa7d051a1cba9866a2071138e60e7b6d6 100644 (file)
@@ -118,8 +118,9 @@ struct FunctionRNA {
        /* callback to execute the function */
        CallFunc call;
 
-       /* parameter for the return value */
-       PropertyRNA *ret;
+       /* parameter for the return value
+        * note: this is only the C return value, rna functions can have multiple return values */
+       PropertyRNA *c_ret;
 };
 
 struct PropertyRNA {
index c8f0a29ca64e6e161ab2de8723edcdc75a11e58f..fd28fa04c068d0975ffd68dfcb6922541dca812e 100644 (file)
@@ -2564,11 +2564,13 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
        PointerRNA funcptr;
        ParameterList parms;
        ParameterIterator iter;
-       PropertyRNA *pret, *parm;
+       PropertyRNA *parm;
        PyObject *ret, *item;
-       int i, args_len, parms_len, flag, err= 0, kw_tot= 0, kw_arg;
+       int i, args_len, parms_len, ret_len, flag, err= 0, kw_tot= 0, kw_arg;
        const char *parm_id;
-       void *retdata= NULL;
+
+       PropertyRNA *pret_single= NULL;
+       void *retdata_single= NULL;
 
        /* Should never happen but it does in rare cases */
        if(self_ptr==NULL) {
@@ -2586,12 +2588,12 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
         * the same ID as the functions. */
        RNA_pointer_create(self_ptr->id.data, &RNA_Function, self_func, &funcptr);
 
-       pret= RNA_function_return(self_func);
        args_len= PyTuple_GET_SIZE(args);
 
        RNA_parameter_list_create(&parms, self_ptr, self_func);
        RNA_parameter_list_begin(&parms, &iter);
-       parms_len = RNA_parameter_list_size(&parms);
+       parms_len= RNA_parameter_list_size(&parms);
+       ret_len= 0;
 
        if(args_len + (kw ? PyDict_Size(kw):0) > parms_len) {
                PyErr_Format(PyExc_TypeError, "%.200s.%.200s(): takes at most %d arguments, got %d", RNA_struct_identifier(self_ptr->type), RNA_function_identifier(self_func), parms_len, args_len);
@@ -2601,14 +2603,20 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
        /* parse function parameters */
        for (i= 0; iter.valid && err==0; RNA_parameter_list_next(&iter)) {
                parm= iter.parm;
+               flag= RNA_property_flag(parm);
+
+               /* only useful for single argument returns, we'll need another list loop for multiple */
+               if (flag & PROP_RETURN) {
+                       ret_len++;
+                       if (pret_single==NULL) {
+                               pret_single= parm;
+                               retdata_single= iter.data;
+                       }
 
-               if (parm==pret) {
-                       retdata= iter.data;
                        continue;
                }
 
                parm_id= RNA_property_identifier(parm);
-               flag= RNA_property_flag(parm);
                item= NULL;
 
                if ((i < args_len) && (flag & PROP_REQUIRED)) {
@@ -2740,8 +2748,25 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
 
                /* return value */
                if(err==0) {
-                       if(pret) {
-                               ret= pyrna_param_to_py(&funcptr, pret, retdata);
+                       if (ret_len > 0) {
+                               if (ret_len > 1) {
+                                       ret= PyTuple_New(ret_len);
+                                       i= 0; /* arg index */
+
+                                       RNA_parameter_list_begin(&parms, &iter);
+
+                                       for(; iter.valid; RNA_parameter_list_next(&iter)) {
+                                               parm= iter.parm;
+                                               flag= RNA_property_flag(parm);
+
+                                               if (flag & PROP_RETURN)
+                                                       PyTuple_SET_ITEM(ret, i++, pyrna_param_to_py(&funcptr, parm, iter.data));
+                                       }
+
+                                       RNA_parameter_list_end(&iter);
+                               }
+                               else
+                                       ret= pyrna_param_to_py(&funcptr, pret_single, retdata_single);
 
                                /* possible there is an error in conversion */
                                if(ret==NULL)
@@ -3980,15 +4005,18 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
 
 extern void BPY_update_modules( void ); //XXX temp solution
 
+/* TODO - multiple return values like with rna functions */
 static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *parms)
 {
        PyObject *args;
        PyObject *ret= NULL, *py_class, *py_class_instance, *item, *parmitem;
-       PropertyRNA *pret= NULL, *parm;
+       PropertyRNA *parm;
        ParameterIterator iter;
        PointerRNA funcptr;
-       void *retdata= NULL;
-       int err= 0, i, flag;
+       int err= 0, i, flag, ret_len=0;
+
+       PropertyRNA *pret_single= NULL;
+       void *retdata_single= NULL;
 
        PyGILState_STATE gilstate;
 
@@ -4014,10 +4042,9 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
 
        if (py_class_instance) { /* Initializing the class worked, now run its invoke function */
                item= PyObject_GetAttrString(py_class, RNA_function_identifier(func));
-               flag= RNA_function_flag(func);
+//             flag= RNA_function_flag(func);
 
                if(item) {
-                       pret= RNA_function_return(func);
                        RNA_pointer_create(NULL, &RNA_Function, func, &funcptr);
 
                        args = PyTuple_New(rna_function_arg_count(func)); /* first arg is included in 'item' */
@@ -4028,9 +4055,16 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
                        /* parse function parameters */
                        for (i= 1; iter.valid; RNA_parameter_list_next(&iter)) {
                                parm= iter.parm;
+                               flag= RNA_property_flag(parm);
+
+                               /* only useful for single argument returns, we'll need another list loop for multiple */
+                               if (flag & PROP_RETURN) {
+                                       ret_len++;
+                                       if (pret_single==NULL) {
+                                               pret_single= parm;
+                                               retdata_single= iter.data;
+                                       }
 
-                               if (parm==pret) {
-                                       retdata= iter.data;
                                        continue;
                                }
 
@@ -4060,8 +4094,37 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
                err= -1;
        }
        else {
-               if(retdata)
-                       err= pyrna_py_to_prop(&funcptr, pret, retdata, ret, "calling class function:");
+               if(ret_len==1) {
+                       err= pyrna_py_to_prop(&funcptr, pret_single, retdata_single, ret, "calling class function:");
+               }
+               else if (ret_len > 1) {
+
+                       if(PyTuple_Check(ret)==0) {
+                               PyErr_Format(PyExc_RuntimeError, "expected class %.200s, function %.200s to return a tuple of size %d.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func), ret_len);
+                               err= -1;
+                       }
+                       else if (PyTuple_GET_SIZE(ret) != ret_len) {
+                               PyErr_Format(PyExc_RuntimeError, "class %.200s, function %.200s to returned %d items, expected %d.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func), PyTuple_GET_SIZE(ret), ret_len);
+                               err= -1;
+                       }
+                       else {
+
+                               RNA_parameter_list_begin(parms, &iter);
+
+                               /* parse function parameters */
+                               for (i= 0; iter.valid; RNA_parameter_list_next(&iter)) {
+                                       parm= iter.parm;
+                                       flag= RNA_property_flag(parm);
+
+                                       /* only useful for single argument returns, we'll need another list loop for multiple */
+                                       if (flag & PROP_RETURN) {
+                                               err= pyrna_py_to_prop(&funcptr, parm, iter.data, PyTuple_GET_ITEM(ret, i++), "calling class function:");
+                                               if(err)
+                                                       break;
+                                       }
+                               }
+                       }
+               }
                Py_DECREF(ret);
        }