Generate a proper function signature */
| 109 | |
| 110 | /* Generate a proper function signature */ |
| 111 | inline std::string generate_function_signature(const char *type_caster_name_field, |
| 112 | detail::function_record *func_rec, |
| 113 | const std::type_info *const *types, |
| 114 | size_t &type_index, |
| 115 | size_t &arg_index) { |
| 116 | std::string signature; |
| 117 | bool is_starred = false; |
| 118 | // `is_return_value.top()` is true if we are currently inside the return type of the |
| 119 | // signature. Using `@^`/`@$` we can force types to be arg/return types while `@!` pops |
| 120 | // back to the previous state. |
| 121 | std::stack<bool> is_return_value({false}); |
| 122 | // The following characters have special meaning in the signature parsing. Literals |
| 123 | // containing these are escaped with `!`. |
| 124 | std::string special_chars("!@%{}-"); |
| 125 | for (const auto *pc = type_caster_name_field; *pc != '\0'; ++pc) { |
| 126 | const auto c = *pc; |
| 127 | if (c == '{') { |
| 128 | // Write arg name for everything except *args and **kwargs. |
| 129 | // Detect {@*args...} or {@**kwargs...} |
| 130 | is_starred = *(pc + 1) == '@' && *(pc + 2) == '*'; |
| 131 | if (is_starred) { |
| 132 | continue; |
| 133 | } |
| 134 | // Separator for keyword-only arguments, placed before the kw |
| 135 | // arguments start (unless we are already putting an *args) |
| 136 | if (!func_rec->has_args && arg_index == func_rec->nargs_pos) { |
| 137 | signature += "*, "; |
| 138 | } |
| 139 | if (arg_index < func_rec->args.size() && func_rec->args[arg_index].name) { |
| 140 | signature += func_rec->args[arg_index].name; |
| 141 | } else if (arg_index == 0 && func_rec->is_method) { |
| 142 | signature += "self"; |
| 143 | } else { |
| 144 | signature += "arg" + std::to_string(arg_index - (func_rec->is_method ? 1 : 0)); |
| 145 | } |
| 146 | signature += ": "; |
| 147 | } else if (c == '}') { |
| 148 | // Write default value if available. |
| 149 | if (!is_starred && arg_index < func_rec->args.size() |
| 150 | && func_rec->args[arg_index].descr) { |
| 151 | signature += " = "; |
| 152 | signature += detail::replace_newlines_and_squash(func_rec->args[arg_index].descr); |
| 153 | } |
| 154 | // Separator for positional-only arguments (placed after the |
| 155 | // argument, rather than before like * |
| 156 | if (func_rec->nargs_pos_only > 0 && (arg_index + 1) == func_rec->nargs_pos_only) { |
| 157 | signature += ", /"; |
| 158 | } |
| 159 | if (!is_starred) { |
| 160 | arg_index++; |
| 161 | } |
| 162 | } else if (c == '%') { |
| 163 | const std::type_info *t = types[type_index++]; |
| 164 | if (!t) { |
| 165 | pybind11_fail("Internal error while parsing type signature (1)"); |
| 166 | } |
| 167 | if (auto *tinfo = detail::get_type_info(*t)) { |
| 168 | handle th(reinterpret_cast<PyObject *>(tinfo->type)); |
no test coverage detected