See More

#include "message_codec.h" #include "field_codecs.h" #include #include #include namespace TbApiImpl { namespace Python { MessageCodec::MessageCodec(const ClassDescriptors &descriptors, intptr_t num) { buildDecoders(descriptors, num); } MessageCodec::MessageCodec(PythonTbApiModule *tbapi_module, const ClassDescriptors &descriptors, intptr_t num) { tbapi_module_ = tbapi_module; buildDecoders(descriptors, num); } MessageCodec::~MessageCodec() { } void MessageCodec::decode(PyObject *message, DxApi::DataReader &reader) { for (int i = 0; i < field_codecs_.size(); ++i) { PythonRefHolder object(field_codecs_[i]->decode(reader)); PyObject_SetAttr(message, field_codecs_[i]->getKey(), object.getReference()); } } void MessageCodec::encode(PyObject *message, DxApi::DataWriter &writer) { for (int i = 0; i < field_codecs_.size(); ++i) { if (!PyObject_HasAttr(message, field_codecs_[i]->getKey())) { field_codecs_[i]->encode(Py_None, writer); continue; } PythonRefHolder object(PyObject_GetAttr(message, field_codecs_[i]->getKey())); field_codecs_[i]->encode(object.getReference(), writer); } } void MessageCodec::buildDecoders(const ClassDescriptors &descriptors, intptr_t num) { if (descriptors.size() <= 0) return; std::vector<:fieldinfo> fields; collectFields(fields, descriptors, num); field_codecs_ = buildFieldDecoders(fields, descriptors); } void MessageCodec::collectFields(std::vector<:fieldinfo> &fields, const ClassDescriptors &descriptors, intptr_t index) { intptr_t parentIndex = descriptors[index].parentIndex; if (parentIndex >= 0) collectFields(fields, descriptors, parentIndex); for (int i = 0; i < descriptors[index].fields.size(); ++i) fields.push_back(descriptors[index].fields[i]); } std::vector MessageCodec::buildFieldDecoders( std::vector<:fieldinfo> &fields, const ClassDescriptors &descriptors) { std::vector field_codecs; for (int i = 0; i < fields.size(); ++i) { Schema::FieldInfo &field = fields[i]; FieldCodecPtr field_codec = createFieldCodec(field.dataType, field.name, field.relativeTo, descriptors); if (field_codec != nullptr) { field_codecs.push_back(field_codec); codecs_search_map_[field.name] = field_codec; } else { THROW_EXCEPTION("Unable to create decoder for field '%s', type '%s', encoding '%s'", field.name.c_str(), field.dataType.typeName.c_str(), field.dataType.encodingName.c_str()); } } return field_codecs; } FieldCodecPtr MessageCodec::createFieldCodec( Schema::DataType &data_type, std::string &field_name, std::string &relative_to, const ClassDescriptors &descriptors) { std::string temptype = data_type.encodingName.empty() ? data_type.typeName : data_type.encodingName; std::transform(temptype.begin(), temptype.end(), temptype.begin(), ::tolower); std::remove_if(temptype.begin(), temptype.end(), ::isspace); const char *cmpr = temptype.c_str(); if (strcmp("datetime", cmpr) == 0) { return FieldCodecPtr(new TimestampFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (!temptype.compare(0, strlen("decimal64"), "decimal64")) { return FieldCodecPtr(new Decimal64FieldCodec(field_name.c_str(), data_type.isNullable)); } else if (!temptype.compare(0, strlen("decimal"), "decimal")) { return FieldCodecPtr(new FloatFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 63, data_type.isNullable)); } else if (strcmp("ieee32", cmpr) == 0) { return FieldCodecPtr(new FloatFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 32, data_type.isNullable)); } else if (strcmp("ieee64", cmpr) == 0) { return FieldCodecPtr(new FloatFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 64, data_type.isNullable)); } else if (temptype.rfind("binary(", 0) == 0) { return FieldCodecPtr(new FloatFieldCodec(field_name.c_str(), findRelativeTo(relative_to), atoi(temptype.substr(strlen("binary(")).c_str()), data_type.isNullable) ); } else if (strcmp("int8", cmpr) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 8, data_type.isNullable)); } else if (strcmp("int16", cmpr) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 16, data_type.isNullable)); } else if (strcmp("int32", cmpr) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 32, data_type.isNullable)); } else if (strcmp("int48", cmpr) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 48, data_type.isNullable)); } else if (strcmp("int64", cmpr) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 64, data_type.isNullable)); } else if (temptype.rfind("signed(", 0) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), atoi(temptype.substr(strlen("signed(")).c_str()), data_type.isNullable) ); } else if (strcmp("puint30", cmpr) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 30, data_type.isNullable)); } else if (strcmp("puint61", cmpr) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), 61, data_type.isNullable)); } else if (temptype.rfind("unsigned(", 0) == 0) { return FieldCodecPtr(new IntegerFieldCodec(field_name.c_str(), findRelativeTo(relative_to), atoi(temptype.substr(strlen("unsigned(")).c_str()), data_type.isNullable) ); } else if (strcmp("pinterval", cmpr) == 0) { return FieldCodecPtr(new IntervalFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("interval", cmpr) == 0) { return FieldCodecPtr(new IntervalFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("timeofday", cmpr) == 0) { return FieldCodecPtr(new TimeOfDayFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("binary", cmpr) == 0) { return FieldCodecPtr(new BinaryFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("boolean", cmpr) == 0) { return FieldCodecPtr(new BooleanFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("char", cmpr) == 0) { return FieldCodecPtr(new CharFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("utf8", cmpr) == 0) { return FieldCodecPtr(new Utf8FieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("ascii", cmpr) == 0) { return FieldCodecPtr(new AsciiFieldCodec(field_name.c_str(), data_type.isNullable)); } else if (strcmp("enum", cmpr) == 0) { int32_t index = findDescriptorByGuid(descriptors, data_type.descriptorGuid); if (index == INT32_MIN) THROW_EXCEPTION("Unknown enum type: %s.", data_type.descriptorGuid.c_str()); return FieldCodecPtr(new EnumFieldCodec(field_name.c_str(), descriptors[index], data_type.isNullable)); } else if (strcmp("array", cmpr) == 0) { if (data_type.elementType == nullptr) THROW("Empty array element type."); std::string new_field_name = ""; std::string new_relative_to = ""; FieldCodecPtr element_codec( createFieldCodec(*data_type.elementType, new_field_name, new_relative_to, descriptors) ); return FieldCodecPtr(new ArrayFieldCodec(field_name.c_str(), element_codec, data_type.isNullable)); } else if (strcmp("object", cmpr) == 0) { std::vector codecs; std::vector<:string> types; for (std::string &type : data_type.types) { int32_t index = findDescriptorByGuid(descriptors, type); if (index == INT32_MIN) THROW_EXCEPTION("Unknown object type: %s.", type.c_str()); codecs.push_back(MessageCodecPtr(new MessageCodec(tbapi_module_, descriptors, index))); types.push_back(descriptors[index].className); } return FieldCodecPtr( new ObjectFieldCodec(field_name.c_str(), tbapi_module_, types, codecs, data_type.isNullable) ); } else if (!temptype.compare(0, strlen("alphanumeric("), "alphanumeric(")) { return FieldCodecPtr( new AlphanumericFieldCodec( field_name.c_str(), atoi(temptype.substr(strlen("alphanumeric(")).c_str()), data_type.isNullable ) ); }; return nullptr; } int32_t MessageCodec::findDescriptorByGuid(const ClassDescriptors &descriptors, const std::string &guid) { int32_t index = INT32_MIN; for (int i = 0; i < descriptors.size(); ++i) { if (descriptors[i].guid == guid) { index = i; break; } } return index; } template CODEC_TYPE MessageCodec::findRelativeTo(std::string &relativeTo) { CODEC_TYPE relative_to = NULL; auto it = codecs_search_map_.find(relativeTo); if (it != codecs_search_map_.end()) relative_to = dynamic_cast(it->second.get()); return relative_to; } } }