예제 #1
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::RegisterCodec(int opcode, PyObject *codec)
{
    if (_codec != This::BinaryCodec)
    {
        pyllbc_SetError("current codec strategy not BINARY, don't need register codec");
        return LLBC_RTN_FAILED;
    }
    else if (_llbcSvcType == LLBC_IService::Raw)
    {
        pyllbc_SetError("RAW type service don't need register codec");
        return LLBC_RTN_FAILED;
    }
    else if (!PyCallable_Check(codec))
    {
        pyllbc_SetError("codec not callable");
        return LLBC_RTN_FAILED;
    }

    if (!_codecs.insert(std::make_pair(opcode, codec)).second)
    {
        LLBC_String err;
        pyllbc_SetError(err.append_format(
            "repeat to register specify opcode's codec, opcode: %d", opcode));

        return LLBC_RTN_FAILED;
    }

    Py_INCREF(codec);

    return LLBC_RTN_OK;
}
예제 #2
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::UnifyPreSubscribe(PyObject *preHandler, int flags)
{
    if (_started)
    {
        pyllbc_SetError("service already started", LLBC_ERROR_INITED);
        return LLBC_RTN_FAILED;
    }

    pyllbc_PacketHandler *wrapHandler = LLBC_New1(pyllbc_PacketHandler, 0);
    if (wrapHandler->SetHandler(preHandler) != LLBC_RTN_OK)
    {
        LLBC_Delete(wrapHandler);
        return LLBC_RTN_FAILED;
    }

    if (_unifyPreHandler)
    {
        pyllbc_SetError("repeat to unify pre-subscribe packet");
        return LLBC_RTN_FAILED;
    }

    _unifyPreHandler = wrapHandler;
    _llbcSvc->UnifyPreSubscribe(_cppFacade, &pyllbc_Facade::OnDataUnifyPreReceived);

    return LLBC_RTN_OK;
}
예제 #3
0
int pyllbc_PackLemma_Dict::Write(pyllbc_Stream *stream, PyObject *values)
{
    if (UNLIKELY(_state != Base::Done))
    {
        pyllbc_SetError("could not pack not done dict-lemma");
        return LLBC_RTN_FAILED;
    }

    if (!PyDict_Check(values))
    {
        pyllbc_SetError("dict-lemma could not pack non-dict type object");
        return LLBC_RTN_FAILED;
    }

    const Py_ssize_t len = PyDict_Size(values);
    LLBC_Stream &llbcStream = stream->GetLLBCStream();

#if _M_X64
    llbcStream.WriteSInt32(static_cast<sint32>(len));
#else
    llbcStream.WriteSInt32(len);
#endif

    Py_ssize_t pos = 0;
    PyObject *key, *value;
    while (PyDict_Next(values, &pos, &key, &value))
    {
        if (_keyLemma->Write(stream, key) != LLBC_RTN_OK)
            return LLBC_RTN_FAILED;
        if (_valueLemma->Write(stream, value) != LLBC_RTN_OK)
            return LLBC_RTN_FAILED;
    }

    return LLBC_RTN_OK;
}
예제 #4
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::PreSubscribe(int opcode, PyObject *preHandler, int flags)
{
    if (_started)
    {
        pyllbc_SetError("service already started", LLBC_ERROR_INITED);
        return LLBC_RTN_FAILED;
    }
    else if (_llbcSvcType == LLBC_IService::Raw && opcode != 0)
    {
        pyllbc_SetError("RAW type service could not pre-subscribe opcode != 0's packet", LLBC_ERROR_INVALID);
        return LLBC_RTN_FAILED;
    }

    pyllbc_PacketHandler *wrapHandler = LLBC_New1(pyllbc_PacketHandler, opcode);
    if (wrapHandler->SetHandler(preHandler) != LLBC_RTN_OK)
    {
        LLBC_Delete(wrapHandler);
        return LLBC_RTN_FAILED;
    }

    if (!_preHandlers.insert(std::make_pair(opcode, wrapHandler)).second)
    {
        LLBC_Delete(wrapHandler);

        LLBC_String err;
        pyllbc_SetError(err.format(
            "repeat to pre-subscribe opcode: %d, the opcode already pre-subscribed", opcode), LLBC_ERROR_REPEAT);

        return LLBC_RTN_FAILED;
    }

    _llbcSvc->PreSubscribe(opcode, _cppFacade, &pyllbc_Facade::OnDataPreReceived);

    return LLBC_RTN_OK;
}
예제 #5
0
PyObject *pyllbc_PackLemma_Dict::Read(pyllbc_Stream *stream)
{
    if (UNLIKELY(_state != Base::Done))
    {
        pyllbc_SetError("dict-lemma not done for unpack data");
        return NULL;
    }

    int len;
    LLBC_Stream &llbcStream = stream->GetLLBCStream();
    if (!llbcStream.ReadSInt32(len))
    {
        pyllbc_SetError("not enough bytes to unpack dict data(head area)");
        return NULL;
    }

    if (UNLIKELY(len < 0))
    {
        pyllbc_SetError("when unpacking dict data, unpack len < 0");
        return NULL;
    }

    PyObject *dict = PyDict_New();
    for (int i = 0; i < len; i++)
    {
        PyObject *key = _keyLemma->Read(stream);
        if (!key)
        {
            Py_DECREF(dict);
            return NULL;
        }

        PyObject *value = _valueLemma->Read(stream);
        if (!value)
        {
            Py_DECREF(key);
            Py_DECREF(dict);

            return NULL;
        }

        if (PyDict_SetItem(dict, key, value) != 0)
        {
            Py_DECREF(value);
            Py_DECREF(key);

            Py_DECREF(dict);

            pyllbc_TransferPyError("when unpack dict data from stream");
            return NULL;
        }

        Py_DECREF(value);
        Py_DECREF(key);
    }

    return dict;
}
예제 #6
0
int pyllbc_PackLemma_Top::Write(pyllbc_Stream *stream, PyObject *values)
{
    if (UNLIKELY(!this->IsDone()))
    {
        pyllbc_SetError("top-lemma not done, could not pack data");
        return LLBC_RTN_FAILED;
    }

    const bool valuesIsNone = pyllbc_TypeDetector::IsNone(values);
    if (valuesIsNone)
    {
        if (!_lemmas.empty())
        {
            pyllbc_SetError("not found any values to pack, but has been specified format character symbol");
            return LLBC_RTN_FAILED;
        }

        return LLBC_RTN_OK;
    }
    else if (!pyllbc_TypeDetector::IsSequence(values))
    {
        pyllbc_SetError("will pack data not iterable");
        return LLBC_RTN_FAILED;
    }
    
    const Py_ssize_t seqSize = PySequence_Size(values);
    if (seqSize != static_cast<Py_ssize_t>(_lemmas.size()))
    {
        LLBC_String errStr;
        pyllbc_SetError(errStr.format(
            "will pack data sequence size[%ld] not equal format character size[%d]", 
            seqSize, _lemmas.size()));

        return LLBC_RTN_FAILED;
    }

    for (Py_ssize_t i = 0; i < seqSize; i++)
    {
        Base *lemma = _lemmas.at(i);
        PyObject *obj = PySequence_GetItem(values, i);
        if (lemma->Write(stream, obj) != LLBC_RTN_OK)
        {
            Py_DECREF(obj);
            return LLBC_RTN_FAILED;
        }

        Py_DECREF(obj);
    }

    return LLBC_RTN_OK;
}
예제 #7
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::Post(PyObject *callable)
{
    if (!PyCallable_Check(callable))
    {
        const LLBC_String objDesc = pyllbc_ObjUtil::GetObjStr(callable);
        pyllbc_SetError(LLBC_String().format("frame callable object not callable: %s", objDesc.c_str()));

        return LLBC_RTN_FAILED;
    }

    if (_handlingBeforeFrameCallables &&
        _handlingAfterFrameCallables)
    {
        pyllbc_SetError("could not push callable object to service, internal error!");
        return LLBC_RTN_FAILED;
    }

    if (_beforeFrameCallables.find(callable) != _beforeFrameCallables.end() ||
        _afterFrameCallables.find(callable) != _afterFrameCallables.end())
    {
        const LLBC_String objDesc = pyllbc_ObjUtil::GetObjStr(callable);
        pyllbc_SetError(LLBC_String().format(
            "repeat to add callable to service, callable: %s", objDesc.c_str()));

        return LLBC_RTN_FAILED;
    }

    Py_INCREF(callable);
    if (_handlingBeforeFrameCallables)
    {
        _afterFrameCallables.insert(callable);
    }
    else
    {
        if (!_handledBeforeFrameCallables)
        {
            _beforeFrameCallables.insert(callable);
        }
        else
        {
            if (!_handlingAfterFrameCallables)
                _afterFrameCallables.insert(callable);
            else
                _beforeFrameCallables.insert(callable);
        }
    }

    return LLBC_RTN_OK;
}
예제 #8
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::Broadcast(int opcode, PyObject *data, int status, PyObject *parts)
{
    // Started check.
    if (UNLIKELY(!this->IsStarted()))
    {
        pyllbc_SetError("service not start");
        return LLBC_RTN_FAILED;
    }

    // Build parts, if exists.
    LLBC_PacketHeaderParts *cLayerParts = NULL;
    if (parts && _llbcSvcType != LLBC_IService::Raw)
    {
        if (!(cLayerParts = this->BuildCLayerParts(parts)))
            return LLBC_RTN_FAILED;
    }

    // Serialize python layer 'data' object to stream.
    LLBC_Stream stream;
    if (this->SerializePyObj2Stream(data, stream) != LLBC_RTN_OK)
    {
        LLBC_XDelete(cLayerParts);
        return LLBC_RTN_FAILED;
    }

    // Send it.
    const void *bytes = stream.GetBuf();
    const size_t len = stream.GetPos();
    return _llbcSvc->Broadcast2(opcode, bytes, len, status, cLayerParts);
}
예제 #9
0
PyObject *pyllbc_PackLemma_Top::Read(pyllbc_Stream *stream)
{
    if (UNLIKELY(!this->IsDone()))
    {
        pyllbc_SetError("top-lemma not done, could not unpack data");
        return NULL;
    }

    size_t idx = 0;
    PyObject *values = PyTuple_New(_lemmas.size());
    for (; idx < _lemmas.size(); idx++)
    {
        PyObject *value;
        Base *lemma = _lemmas[idx];
        if (!(value = lemma->Read(stream)))
            break;

        PyTuple_SET_ITEM(values, idx, value);
    }

    if (idx != _lemmas.size())
    {
        Py_DECREF(values);
        values = NULL;
    }

    return values;
}
예제 #10
0
int pyllbc_PackLemma_Top::Process(Symbol ch, Symbol nextCh)
{
    _state = Base::Error;
    pyllbc_SetError("top level pack-lemma could not accept any character symbols");

    return LLBC_RTN_FAILED;
}
예제 #11
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::SerializePyObj2Stream(PyObject *pyObj, LLBC_Stream &stream)
{
    if (_codec == This::JsonCodec)
    {
        std::string out;
        if (UNLIKELY(pyllbc_ObjCoder::Encode(pyObj, out) != LLBC_RTN_OK))
            return LLBC_RTN_FAILED;

        stream.WriteBuffer(out.data(), out.size());

        return LLBC_RTN_OK;
    }
    else
    {
        // Create python layer Stream instance.
        PyObject *arg = PyTuple_New(2);
        PyTuple_SetItem(arg, 0, PyInt_FromLong(0)); // stream init size = 0.
        
        Py_INCREF(pyObj);
        PyTuple_SetItem(arg, 1, pyObj); // initWrite = pyObj(steal reference).

        PyObject *pyStreamObj = PyObject_CallObject(This::_streamCls, arg);
        if (UNLIKELY(!pyStreamObj))
        {
            Py_DECREF(arg);
            pyllbc_TransferPyError();

            return LLBC_RTN_FAILED;
        }

        // Get cobj property.
        PyObject *cobj = PyObject_GetAttr(pyStreamObj, _keyCObj);
        if (UNLIKELY(!cobj))
        {
            Py_DECREF(pyStreamObj);
            Py_DECREF(arg);

            pyllbc_SetError("could not get llbc.Stream property 'cobj'");

            return LLBC_RTN_FAILED;
        }

        // Convert to pyllbc_Stream *.
        pyllbc_Stream *cstream = NULL;
        PyArg_Parse(cobj, "l", &cstream);

        // Let stream attach to inlStream.
        LLBC_Stream &inlStream = cstream->GetLLBCStream();

        stream.Attach(inlStream);
        (void)inlStream.Detach();
        stream.SetAttachAttr(false);

        Py_DECREF(cobj);
        Py_DECREF(pyStreamObj);
        Py_DECREF(arg);

        return LLBC_RTN_OK;
    }
}
예제 #12
0
int pyllbc_PackLemma_Dict::Process(Base *lemma)
{
    // Param check.
    if (!lemma->IsSerializable())
    {
        _state = Base::Error;
        pyllbc_SetError("dict-lemma could not accept UnSerializable lemma");

        return LLBC_RTN_FAILED;
    }

    // State check.
    if (_state == Base::Done || _state == Base::Error)
    {
        pyllbc_SetError("dict-lemma state is done or error, could not continuing to parse format string");
        return LLBC_RTN_FAILED;
    }
    else if (_state == Base::Begin)
    {
        _state = Base::Error;
        pyllbc_SetError("dict-lemma expect dict begin character: '{', got lemma");

        return LLBC_RTN_FAILED;
    }

    // Key, Value logic check.
    if (_valueLemma)
    {
        _state = Base::Error;
        pyllbc_SetError("dict-lemma expect dict close character'}', but got lemma");

        return LLBC_RTN_FAILED;
    }
    else if (_keyLemma && !_gotKwSep)
    {
        _state = Base::Error;
        pyllbc_SetError("dict-lemma expect dict key-word separator':', but got lemma");
        
        return LLBC_RTN_FAILED;
    }

    (!_keyLemma ? _keyLemma : _valueLemma) = lemma;
    _str.append(lemma->ToString());

    return LLBC_RTN_OK;
}
예제 #13
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::SetCodec(Codec codec)
{
    if (codec != This::JsonCodec &&
        codec != This::BinaryCodec)
    {
        pyllbc_SetError("invalid codec type", LLBC_ERROR_INVALID);
        return LLBC_RTN_FAILED;
    }
    else if (_started)
    {
        pyllbc_SetError("service already start, could not change codec strategy");
        return LLBC_RTN_FAILED;
    }

    if (codec != _codec)
        _codec = codec;

    return LLBC_RTN_OK;
}
예제 #14
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::Subscribe(int opcode, PyObject *handler, int flags)
{
    if (_started)
    {
        pyllbc_SetError("service already started", LLBC_ERROR_INITED);
        return LLBC_RTN_FAILED;
    }
    else if (_llbcSvcType == LLBC_IService::Raw && opcode != 0)
    {
        pyllbc_SetError(LLBC_String().format(
            "RAW type service could not subscribe opcode[%d] != 0's packet", opcode), LLBC_ERROR_INVALID);
        return LLBC_RTN_FAILED;
    }

    _PacketHandlers::const_iterator it = _handlers.find(opcode);
    if (it != _handlers.end())
    {
        const LLBC_String handlerDesc = pyllbc_ObjUtil::GetObjStr(handler);

        LLBC_String err;
        err.append_format("repeat to subscribeopcode: %d:%s, ", opcode, handlerDesc.c_str());
        err.append_format("the opcode already subscribed by ");
        err.append_format("%s", it->second->ToString().c_str());

        pyllbc_SetError(err, LLBC_ERROR_REPEAT);

        return LLBC_RTN_FAILED;
    }

    pyllbc_PacketHandler *wrapHandler = LLBC_New1(pyllbc_PacketHandler, opcode);
    if (wrapHandler->SetHandler(handler) != LLBC_RTN_OK)
    {
        LLBC_Delete(wrapHandler);
        return LLBC_RTN_FAILED;
    }

    _handlers.insert(std::make_pair(opcode, wrapHandler));
    _llbcSvc->Subscribe(opcode, _cppFacade, &pyllbc_Facade::OnDataReceived);

    return LLBC_RTN_OK;
}
예제 #15
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::Send(int sessionId, int opcode, PyObject *data, int status, PyObject *parts)
{
    // Started check.
    if (UNLIKELY(!this->IsStarted()))
    {
        pyllbc_SetError("service not start");
        return LLBC_RTN_FAILED;
    }

    // Build parts, if exists.
    LLBC_PacketHeaderParts *cLayerParts = NULL;
    if (parts && _llbcSvcType != LLBC_IService::Raw)
    {
        if (!(cLayerParts = this->BuildCLayerParts(parts)))
            return LLBC_RTN_FAILED;
    }

    // Serialize python layer 'data' object to stream.
    LLBC_Stream stream;
    const int ret = this->SerializePyObj2Stream(data, stream);
    if (UNLIKELY(ret != LLBC_RTN_OK))
    {
        LLBC_XDelete(cLayerParts);
        return LLBC_RTN_FAILED;
    }

    // Build packet & send.
    LLBC_Packet *packet = LLBC_New(LLBC_Packet);
    packet->Write(stream.GetBuf(), stream.GetPos());

    packet->SetSessionId(sessionId);
    if (_llbcSvcType != LLBC_IService::Raw)
    {
        packet->SetOpcode(opcode);
        packet->SetStatus(status);

        if (cLayerParts)
        {
            cLayerParts->SetToPacket(*packet);
            LLBC_Delete(cLayerParts);
        }
    }

    if (UNLIKELY(_llbcSvc->Send(packet) == LLBC_RTN_FAILED))
    {
        pyllbc_TransferLLBCError(__FILE__, __LINE__);
        return LLBC_RTN_FAILED;
    }

    return LLBC_RTN_OK;
}
예제 #16
0
int pyllbc_ErrorHooker::Install()
{
    if (_installed)
    {
        pyllbc_SetError(LLBC_ERROR_REENTRY);
        return LLBC_FAILED;
    }

    pyllbc_SetErrSetHock(new _SetDeleg(this, &This::Hook_ErrSet));
    pyllbc_SetErrClearHook(new _ClearDeleg(this, &This::Hook_ErrClear));

    _installed = true;
    return LLBC_OK;
}
예제 #17
0
int pyllbc_ScriptIntegrator::Integrate()
{
    if (_builded)
        return LLBC_RTN_OK;

    if (PyRun_SimpleString(_script.c_str()) != 0)
    {
        pyllbc_SetError(PYLLBC_ERROR_COMMON);
        return LLBC_RTN_FAILED;
    }

    _builded = true;

    return LLBC_RTN_OK;
}
예제 #18
0
int pyllbc_PackLemma_Top::Process(Base *lemma)
{
    if (!lemma->IsDone())
    {
        _state = Base::Error;
        pyllbc_SetError("top level lemma could not accept not done lemma");

        return LLBC_RTN_FAILED;
    }

    _state = Base::Accepting;
    _lemmas.push_back(lemma);

    _str.append(lemma->ToString());

    return LLBC_RTN_OK;
}
예제 #19
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::RegisterFacade(PyObject *facade)
{
    if (!_facades.insert(facade).second)
    {
        PyObject *pyFacadeStr = PyObject_Str(facade);
        LLBC_String facadeStr = PyString_AsString(pyFacadeStr);
        Py_DECREF(pyFacadeStr);

        LLBC_String errStr;
        pyllbc_SetError(errStr.format("repeat to register facade: %s", facadeStr.c_str()), LLBC_ERROR_REPEAT);

        return LLBC_RTN_FAILED;
    }

    Py_INCREF(facade);

    return LLBC_RTN_OK;
}
예제 #20
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
int pyllbc_Service::Start(int pollerCount)
{
    if (_started)
    {
        pyllbc_SetError("service already started", LLBC_ERROR_REENTRY);
        return LLBC_RTN_FAILED;
    }

    _started = true;

    if (_llbcSvc->Start(pollerCount) != LLBC_RTN_OK)
    {
        _started = false;
        pyllbc_TransferLLBCError(__FILE__, __LINE__);

        return LLBC_RTN_FAILED;
    }

    return LLBC_RTN_OK;
}
예제 #21
0
void pyllbc_ErrorHooker::TransferHookedErrorToPython()
{
    if (_errCls && !PyErr_Occurred())
    {
        _transfering = true;

        pyllbc_SetError(_errDesc, _llbcErrNo, _errCls);

        // Link the previous traceback, if we holded.
        if (_tbObj)
        {
            PyObject *errType, *errVal, *errTb;
            PyErr_Fetch(&errType, &errVal, &errTb);
            PyErr_NormalizeException(&errType, &errVal, &errTb);

            if (errTb == NULL)
            {
                errTb = _tbObj;
            }
            else
            {
                PyTracebackObject *perTb = 
                    reinterpret_cast<PyTracebackObject *>(errTb);
                while (perTb->tb_next) perTb = perTb->tb_next;
                perTb->tb_next = reinterpret_cast<PyTracebackObject *>(_tbObj);
            }

            _tbObj = NULL;
            PyErr_Restore(errType, errVal, errTb);
        }

        _transfering = false;

        Cleanup();
    }
}
예제 #22
0
int pyllbc_PackLemma_Dict::Process(Symbol ch, Symbol nextCh)
{
    // State logic.
    if (_state == Base::Done && _state == Base::Error)
    {
        pyllbc_SetError("dict-lemma state is done or error, could not continuing to parse format string");
        return LLBC_RTN_FAILED;
    }

    if (_state == Base::Begin)
    {
        if (ch != Base::DictBegin)
        {
            _state = Base::Error;
            pyllbc_SetError("dict-lemma expect dict begin character'{', got %c", ch);

            return LLBC_RTN_FAILED;
        }

        _state = Base::Accepting;
        _str.append(1, static_cast<char>(ch));

        return LLBC_RTN_OK;
    }

    // Key-Word separator & dict close character('}') logic.
    if (ch == Base::DictKWSep)
    {
        if (!_keyLemma)
        {
            _state = Base::Error;
            pyllbc_SetError("dict-lemma expect key lemma, got key-word separator");

            return LLBC_RTN_FAILED;
        }
        else if (_valueLemma)
        {
            _state = Base::Error;
            pyllbc_SetError("dict-lemma expect dict close character '}', got key-word separator");

            return LLBC_RTN_FAILED;
        }

        _gotKwSep = true;
        _str.append(1, static_cast<char>(ch));

        return LLBC_RTN_OK;
    }
    else if (ch == Base::DictEnd)
    {
        if (!_keyLemma || !_valueLemma)
        {
            _state = Base::Error;
            pyllbc_SetError("dict-lemma not done, but got dict close character '}'");

            return LLBC_RTN_FAILED;
        }

        _state = Base::Done;
        _str.append(1, static_cast<char>(ch));

        return LLBC_RTN_OK;
    }

    const SymbolGroup &raw = GroupedSymbol::Raw();
    if (raw.find(ch) == raw.end())
    {
        _state = Base::Error;
        pyllbc_SetError("dict-lemma could direct process non-raw type format character: %c", ch);

        return LLBC_RTN_FAILED;
    }

    Base *lemma = LLBC_New(pyllbc_PackLemma_Raw);
    if (lemma->Process(ch) != LLBC_RTN_OK)
    {
        delete lemma;
        _state = Base::Error;

        return LLBC_RTN_FAILED;
    }

    if (this->Process(lemma) != LLBC_RTN_OK)
    {
        delete lemma;
        return LLBC_RTN_FAILED;
    }

    return LLBC_RTN_OK;
}
예제 #23
0
파일: PyService.cpp 프로젝트: mr-kelly/llbc
LLBC_PacketHeaderParts *pyllbc_Service::BuildCLayerParts(PyObject *pyLayerParts)
{
    // Python layer parts(dict type) convert rules describe:
    //   python type       c++ type
    // --------------------------
    //   int/long/bool -->   sint64
    //     float4/8    -->  float/double
    //   str/bytearray -->  LLBC_String

    if (!PyDict_Check(pyLayerParts))
    {
        pyllbc_SetError("parts instance not dict type");
        return NULL;
    }

    LLBC_PacketHeaderParts *cLayerParts = LLBC_New(LLBC_PacketHeaderParts);

    Py_ssize_t pos = 0;
    PyObject *key, *value;
    while (PyDict_Next(pyLayerParts, &pos, &key, &value)) // key & value are borrowed.
    {
        const int serialNo = static_cast<int>(PyInt_AsLong(key));
        if (UNLIKELY(serialNo == -1 && PyErr_Occurred()))
        {
            pyllbc_TransferPyError("When fetch header part serial no");
            LLBC_Delete(cLayerParts);

            return NULL;
        }

        // Value type check order:
        //   int->
        //     str->
        //       float->
        //         long->
        //           bool->
        //             bytearray->
        //               other objects
        if (PyInt_CheckExact(value))
        {
            const sint64 cValue = PyInt_AS_LONG(value);
            cLayerParts->SetPart<sint64>(serialNo, cValue);
        }
        else if (PyString_CheckExact(value))
        {
            char *strBeg;
            Py_ssize_t strLen;
            if (UNLIKELY(PyString_AsStringAndSize(value, &strBeg, &strLen) == -1))
            {
                pyllbc_TransferPyError("When fetch header part value");
                LLBC_Delete(cLayerParts);

                return NULL;
            }

            cLayerParts->SetPart(serialNo, strBeg, strLen);

        }
        else if (PyFloat_CheckExact(value))
        {
            const double cValue = PyFloat_AS_DOUBLE(value);
            cLayerParts->SetPart<double>(serialNo, cValue);
        }
        else if (PyLong_CheckExact(value))
        {
            const sint64 cValue = PyLong_AsLongLong(value);
            cLayerParts->SetPart<sint64>(serialNo, cValue);
        }
        else if (PyBool_Check(value))
        {
            const int pyBoolCheck = PyObject_IsTrue(value);
            if (UNLIKELY(pyBoolCheck == -1))
            {
                pyllbc_TransferPyError("when fetch header part value");
                LLBC_Delete(cLayerParts);

                return NULL;
            }

            cLayerParts->SetPart<uint8>(serialNo, pyBoolCheck);
        }
        else if (PyByteArray_CheckExact(value))
        {
            char *bytesBeg = PyByteArray_AS_STRING(value);
            Py_ssize_t bytesLen = PyByteArray_GET_SIZE(value);

            cLayerParts->SetPart(serialNo, bytesBeg, bytesLen);
        }
        else // Other types, we simple get the object string representations.
        {
            LLBC_String strRepr = pyllbc_ObjUtil::GetObjStr(value);
            if (UNLIKELY(strRepr.empty() && PyErr_Occurred()))
            {
                LLBC_Delete(cLayerParts);
                return NULL;
            }

            cLayerParts->SetPart(serialNo, strRepr.data(), strRepr.size());
        }
    }

    return cLayerParts;
}