in thrift/lib/py/protocol/fastproto.cpp [283:615]
static bool encode_impl(
Writer* writer,
PyObject* value,
PyObject* typeargs,
TType type,
int utf8strings) {
switch (type) {
case TType::T_BOOL: {
int v = PyObject_IsTrue(value);
if (v == -1) {
return false;
}
writer->writeBool(v == 1);
break;
}
case TType::T_I08: {
int32_t val;
if (!parse_pyint(value, &val, INT8_MIN, INT8_MAX)) {
return false;
}
writer->writeByte((int8_t)val);
break;
}
case TType::T_I16: {
int32_t val;
if (!parse_pyint(value, &val, INT16_MIN, INT16_MAX)) {
return false;
}
writer->writeI16((int16_t)val);
break;
}
case TType::T_I32: {
int32_t val;
if (!parse_pyint(value, &val, INT32_MIN, INT32_MAX)) {
return false;
}
writer->writeI32(val);
break;
}
case TType::T_I64: {
int64_t val = PyLong_AsLongLong(value);
if (INT_CONV_ERROR_OCCURRED(val)) {
return false;
}
if (!CHECK_RANGE(val, INT64_MIN, INT64_MAX)) {
PyErr_SetString(PyExc_OverflowError, "int out of range");
return false;
}
writer->writeI64(val);
break;
}
case TType::T_DOUBLE: {
double val;
if (!parse_pyfloat(value, &val)) {
return false;
}
writer->writeDouble(val);
break;
}
case TType::T_FLOAT: {
double val;
if (!parse_pyfloat(value, &val)) {
return false;
}
writer->writeFloat((float)val);
break;
}
case TType::T_STRING: {
bool encoded = false;
Py_ssize_t len;
#if PY_MAJOR_VERSION >= 3
if (!PyBytes_Check(value)) {
value = PyUnicode_AsUTF8String(value);
if (value == nullptr) {
PyErr_SetString(PyExc_TypeError, "can not encode");
return false;
}
encoded = true;
}
len = PyBytes_Size(value);
#else
if (utf8strings && value->ob_type == &PyUnicode_Type) {
value = PyUnicode_AsUTF8String(value);
if (value == nullptr) {
PyErr_SetString(PyExc_TypeError, "can not encode using utf8");
return false;
}
encoded = true;
}
len = PyString_Size(value);
#endif
if (!check_ssize_t_32(len)) {
return false;
}
#if PY_MAJOR_VERSION >= 3
folly::StringPiece str(PyBytes_AsString(value), len);
#else
folly::StringPiece str(PyString_AsString(value), len);
#endif
writer->writeString(str);
if (encoded) {
Py_DECREF(value);
}
break;
}
case TType::T_LIST:
case TType::T_SET: {
Py_ssize_t len;
SetListTypeArgs parsedargs;
PyObject* item;
PyObject* iterator;
if (!parse_set_list_args(&parsedargs, typeargs)) {
return false;
}
len = PyObject_Length(value);
if (!check_ssize_t_32(len)) {
return false;
}
writer->writeListBegin(parsedargs.element_type, (uint32_t)len);
iterator = PyObject_GetIter(value);
if (iterator == nullptr) {
return false;
}
while ((item = PyIter_Next(iterator))) {
if (!encode_impl(
writer,
item,
parsedargs.typeargs,
parsedargs.element_type,
utf8strings)) {
Py_DECREF(item);
Py_DECREF(iterator);
return false;
}
Py_DECREF(item);
}
Py_DECREF(iterator);
writer->writeListEnd();
if (PyErr_Occurred()) {
return false;
}
break;
}
case TType::T_MAP: {
PyObject *k, *v;
Py_ssize_t pos = 0, len;
MapTypeArgs parsedargs;
len = PyDict_Size(value);
if (!check_ssize_t_32(len)) {
return false;
}
if (!parse_map_args(&parsedargs, typeargs)) {
return false;
}
writer->writeMapBegin(parsedargs.ktype, parsedargs.vtype, (uint32_t)len);
while (PyDict_Next(value, &pos, &k, &v)) {
Py_INCREF(k);
Py_INCREF(v);
if (!encode_impl(
writer,
k,
parsedargs.ktypeargs,
parsedargs.ktype,
utf8strings) ||
!encode_impl(
writer,
v,
parsedargs.vtypeargs,
parsedargs.vtype,
utf8strings)) {
Py_DECREF(k);
Py_DECREF(v);
return false;
}
Py_DECREF(k);
Py_DECREF(v);
}
writer->writeMapEnd();
break;
}
case TType::T_STRUCT: {
StructTypeArgs parsedargs;
if (!parse_struct_args(&parsedargs, typeargs)) {
return false;
}
Py_ssize_t nspec = PyTuple_Size(parsedargs.spec);
if (nspec == -1) {
return false;
}
auto guard = folly::makeDismissedGuard([&] { Py_DECREF(value); });
if (parsedargs.adapter != Py_None && value != Py_None) {
value = PyObject_CallMethodObjArgs(
parsedargs.adapter, INTERN_STRING(to_thrift), value, nullptr);
if (!value) {
return false;
}
guard.rehire();
}
if (parsedargs.isunion) {
// Union only has a field and a value.
writer->writeStructBegin("");
PyObject* field = PyObject_GetAttrString(value, "field");
if (!field) {
return false;
}
int fid = static_cast<int>(AS_LONG(field));
PyObject* spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, fid);
if (spec_tuple != Py_None) {
StructItemSpec parsedspec;
PyObject* instval = nullptr;
if (!parse_struct_item_spec(&parsedspec, spec_tuple)) {
return false;
}
instval = PyObject_GetAttrString(value, "value");
if (!instval) {
return false;
}
if (instval == Py_None) {
Py_DECREF(instval);
return false;
}
#if PY_MAJOR_VERSION >= 3
const char* fieldname = PyUnicode_AsUTF8(parsedspec.attrname);
#else
const char* fieldname = PyString_AsString(parsedspec.attrname);
#endif
writer->writeFieldBegin(fieldname, parsedspec.type, parsedspec.tag);
if (!encode_impl(
writer,
instval,
parsedspec.typeargs,
parsedspec.type,
utf8strings)) {
Py_DECREF(instval);
return false;
}
Py_DECREF(instval);
writer->writeFieldEnd();
}
writer->writeFieldStop();
writer->writeStructEnd();
break;
}
// Both binary and compact ignore the struct name.
writer->writeStructBegin("");
for (Py_ssize_t i = 0; i < nspec; i++) {
StructItemSpec parsedspec;
PyObject* spec_tuple;
PyObject* instval = nullptr;
spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i);
if (spec_tuple == Py_None) {
continue;
}
if (!parse_struct_item_spec(&parsedspec, spec_tuple)) {
return false;
}
instval = PyObject_GetAttr(value, parsedspec.attrname);
if (!instval) {
return false;
}
if (instval == Py_None) {
Py_DECREF(instval);
continue;
}
#if PY_MAJOR_VERSION >= 3
const char* fieldname = PyUnicode_AsUTF8(parsedspec.attrname);
#else
const char* fieldname = PyString_AsString(parsedspec.attrname);
#endif
writer->writeFieldBegin(fieldname, parsedspec.type, parsedspec.tag);
if (!encode_impl(
writer,
instval,
parsedspec.typeargs,
parsedspec.type,
utf8strings)) {
Py_DECREF(instval);
return false;
}
Py_DECREF(instval);
writer->writeFieldEnd();
}
writer->writeFieldStop();
writer->writeStructEnd();
break;
}
case TType::T_STOP:
case TType::T_VOID:
case TType::T_UTF8:
case TType::T_UTF16:
case TType::T_U64:
case TType::T_STREAM:
default:
PyErr_SetString(PyExc_TypeError, "Unexpected TType");
return false;
}
return true;
}