penguin-wwy commented on code in PR #1690:
URL: https://github.com/apache/fury/pull/1690#discussion_r1897960999


##########
python/pyfury/_serialization.pyx:
##########
@@ -1517,39 +1140,52 @@ cdef class 
Int16Serializer(CrossLanguageCompatibleSerializer):
 
 @cython.final
 cdef class Int32Serializer(CrossLanguageCompatibleSerializer):
-    cpdef inline int16_t get_xtype_id(self):
-        return FuryType.INT32.value
-
     cpdef inline write(self, Buffer buffer, value):
-        buffer.write_int32(value)
+        buffer.write_varint32(value)
 
     cpdef inline read(self, Buffer buffer):
-        return buffer.read_int32()
+        return buffer.read_varint32()
 
 
 @cython.final
 cdef class Int64Serializer(CrossLanguageCompatibleSerializer):
-    cpdef inline int16_t get_xtype_id(self):
-        return FuryType.INT64.value
-
     cpdef inline xwrite(self, Buffer buffer, value):
-        buffer.write_int64(value)
+        buffer.write_varint64(value)
 
     cpdef inline xread(self, Buffer buffer):
-        return buffer.read_int64()
+        return buffer.read_varint64()
 
     cpdef inline write(self, Buffer buffer, value):
         buffer.write_varint64(value)
 
     cpdef inline read(self, Buffer buffer):
         return buffer.read_varint64()
 
+cdef int64_t INT8_MIN_VALUE = -1 << 7
+cdef int64_t INT8_MAX_VALUE = 1 << 7 - 1
+cdef int64_t INT16_MIN_VALUE = -1 << 15
+cdef int64_t INT16_MAX_VALUE = 1 << 15 - 1
+cdef int64_t INT32_MIN_VALUE = -1 << 31
+cdef int64_t INT32_MAX_VALUE = 1 << 31 - 1
+cdef float FLOAT32_MIN_VALUE = 1.17549e-38
+cdef float FLOAT32_MAX_VALUE = 3.40282e+38
+
 
 @cython.final
-cdef class FloatSerializer(CrossLanguageCompatibleSerializer):
-    cpdef inline int16_t get_xtype_id(self):
-        return FuryType.FLOAT.value
+cdef class DynamicIntSerializer(CrossLanguageCompatibleSerializer):
+    cpdef inline xwrite(self, Buffer buffer, value):
+        # TOTO(chaokunyang) check value range and write type and value

Review Comment:
   ```suggestion
           # TODO(chaokunyang) check value range and write type and value
   ```



##########
python/pyfury/_serialization.pyx:
##########
@@ -1570,10 +1203,20 @@ cdef class 
DoubleSerializer(CrossLanguageCompatibleSerializer):
 
 
 @cython.final
-cdef class StringSerializer(CrossLanguageCompatibleSerializer):
-    cpdef inline int16_t get_xtype_id(self):
-        return FuryType.STRING.value
+cdef class DynamicFloatSerializer(CrossLanguageCompatibleSerializer):
+    cpdef inline xwrite(self, Buffer buffer, value):
+        # TOTO(chaokunyang) check value range and write type and value

Review Comment:
   ```suggestion
           # TODO(chaokunyang) check value range and write type and value
   ```



##########
python/pyfury/_registry.py:
##########
@@ -0,0 +1,627 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import array
+import dataclasses
+import datetime
+import enum
+import functools
+import logging
+from typing import TypeVar, Union
+from enum import Enum
+
+from pyfury._serialization import ENABLE_FURY_CYTHON_SERIALIZATION
+from pyfury import Language
+from pyfury.error import TypeUnregisteredError
+
+from pyfury.serializer import (
+    Serializer,
+    Numpy1DArraySerializer,
+    NDArraySerializer,
+    PyArraySerializer,
+    DynamicPyArraySerializer,
+    _PickleStub,
+    PickleStrongCacheStub,
+    PickleCacheStub,
+    NoneSerializer,
+    BooleanSerializer,
+    ByteSerializer,
+    Int16Serializer,
+    Int32Serializer,
+    Int64Serializer,
+    DynamicIntSerializer,
+    FloatSerializer,
+    DoubleSerializer,
+    DynamicFloatSerializer,
+    StringSerializer,
+    DateSerializer,
+    TimestampSerializer,
+    BytesSerializer,
+    ListSerializer,
+    TupleSerializer,
+    MapSerializer,
+    SetSerializer,
+    EnumSerializer,
+    SliceSerializer,
+    PickleCacheSerializer,
+    PickleStrongCacheSerializer,
+    PickleSerializer,
+)
+from pyfury._struct import ComplexObjectSerializer
+from pyfury.buffer import Buffer
+from pyfury.meta.metastring import MetaStringEncoder, MetaStringDecoder
+from pyfury.type import (
+    TypeId,
+    Int8Type,
+    Int16Type,
+    Int32Type,
+    Int64Type,
+    Float32Type,
+    Float64Type,
+    load_class,
+)
+from pyfury._fury import (
+    DYNAMIC_TYPE_ID,
+    # preserve 0 as flag for class id not set in ClassInfo`
+    NO_CLASS_ID,
+    PYINT_CLASS_ID,
+    PYFLOAT_CLASS_ID,
+    PYBOOL_CLASS_ID,
+    STRING_CLASS_ID,
+    PICKLE_CLASS_ID,
+    PICKLE_STRONG_CACHE_CLASS_ID,
+    PICKLE_CACHE_CLASS_ID,
+)
+
+try:
+    import numpy as np
+except ImportError:
+    np = None
+
+logger = logging.getLogger(__name__)
+
+
+if ENABLE_FURY_CYTHON_SERIALIZATION:
+    from pyfury._serialization import ClassInfo
+else:
+
+    class ClassInfo:
+        __slots__ = (
+            "cls",
+            "type_id",
+            "serializer",
+            "namespace_bytes",
+            "typename_bytes",
+            "dynamic_type",
+        )
+
+        def __init__(
+            self,
+            cls: type = None,
+            type_id: int = NO_CLASS_ID,
+            serializer: Serializer = None,
+            namespace_bytes=None,
+            typename_bytes=None,
+            dynamic_type: bool = False,
+        ):
+            self.cls = cls
+            self.type_id = type_id
+            self.serializer = serializer
+            self.namespace_bytes = namespace_bytes
+            self.typename_bytes = typename_bytes
+            self.dynamic_type = dynamic_type
+
+        def __repr__(self):
+            return (
+                f"ClassInfo(cls={self.cls}, type_id={self.type_id}, "
+                f"serializer={self.serializer})"
+            )
+
+
+class ClassResolver:
+    __slots__ = (
+        "fury",
+        "_metastr_to_str",
+        "_type_id_counter",
+        "_classes_info",
+        "_hash_to_metastring",
+        "_metastr_to_class",
+        "_hash_to_classinfo",
+        "_dynamic_id_to_classinfo_list",
+        "_dynamic_id_to_metastr_list",
+        "_dynamic_write_string_id",
+        "_dynamic_written_metastr",
+        "_ns_type_to_classinfo",
+        "_named_type_to_classinfo",
+        "namespace_encoder",
+        "namespace_decoder",
+        "typename_encoder",
+        "typename_decoder",
+        "require_registration",
+        "metastring_resolver",
+        "language",
+        "_type_id_to_classinfo",
+    )
+
+    def __init__(self, fury):
+        self.fury = fury
+        self.metastring_resolver = fury.metastring_resolver
+        self.language = fury.language
+        self.require_registration = fury.require_class_registration
+        self._metastr_to_str = dict()
+        self._metastr_to_class = dict()
+        self._hash_to_metastring = dict()
+        self._hash_to_classinfo = dict()
+        self._dynamic_written_metastr = []
+        self._type_id_to_classinfo = dict()
+        self._type_id_counter = PICKLE_CACHE_CLASS_ID + 1
+        self._dynamic_write_string_id = 0
+        # hold objects to avoid gc, since `flat_hash_map/vector` doesn't
+        # hold python reference.
+        self._classes_info = dict()
+        self._ns_type_to_classinfo = dict()
+        self._named_type_to_classinfo = dict()
+        self.namespace_encoder = MetaStringEncoder(".", "_")
+        self.namespace_decoder = MetaStringDecoder(".", "_")
+        self.typename_encoder = MetaStringEncoder("$", "_")
+        self.typename_decoder = MetaStringDecoder("$", "_")
+
+    def initialize(self):
+        if self.fury.language == Language.PYTHON:
+            self._initialize_py()
+        else:
+            self._initialize_xlang()
+
+    def _initialize_py(self):
+        register = functools.partial(self._register_type, internal=True)
+        register(int, type_id=PYINT_CLASS_ID, serializer=Int64Serializer)
+        register(float, type_id=PYFLOAT_CLASS_ID, serializer=DoubleSerializer)
+        register(bool, type_id=PYBOOL_CLASS_ID, serializer=BooleanSerializer)
+        register(str, type_id=STRING_CLASS_ID, serializer=StringSerializer)
+        register(_PickleStub, type_id=PICKLE_CLASS_ID, 
serializer=PickleSerializer)
+        register(
+            PickleStrongCacheStub,
+            type_id=PICKLE_STRONG_CACHE_CLASS_ID,
+            serializer=PickleStrongCacheSerializer(self.fury),
+        )
+        register(
+            PickleCacheStub,
+            type_id=PICKLE_CACHE_CLASS_ID,
+            serializer=PickleCacheSerializer(self.fury),
+        )
+        register(type(None), serializer=NoneSerializer)
+        register(Int8Type, serializer=ByteSerializer)
+        register(Int16Type, serializer=Int16Serializer)
+        register(Int32Type, serializer=Int32Serializer)
+        register(Int64Type, serializer=Int64Serializer)
+        register(Float32Type, serializer=FloatSerializer)
+        register(Float64Type, serializer=DoubleSerializer)
+        register(datetime.date, serializer=DateSerializer)
+        register(datetime.datetime, serializer=TimestampSerializer)
+        register(bytes, serializer=BytesSerializer)
+        register(list, serializer=ListSerializer)
+        register(tuple, serializer=TupleSerializer)
+        register(dict, serializer=MapSerializer)
+        register(set, serializer=SetSerializer)
+        register(enum.Enum, serializer=EnumSerializer)
+        register(slice, serializer=SliceSerializer)
+        try:
+            import pyarrow as pa
+            from pyfury.format.serializer import (
+                ArrowRecordBatchSerializer,
+                ArrowTableSerializer,
+            )
+
+            register(pa.RecordBatch, serializer=ArrowRecordBatchSerializer)
+            register(pa.Table, serializer=ArrowTableSerializer)
+        except Exception:
+            pass
+        for size, ftype, type_id in PyArraySerializer.typecode_dict.values():
+            register(ftype, serializer=PyArraySerializer(self.fury, ftype, 
type_id))
+        register(array.array, serializer=DynamicPyArraySerializer)
+        if np:
+            register(np.ndarray, serializer=NDArraySerializer)
+
+    def _initialize_xlang(self):
+        register = functools.partial(self._register_type, internal=True)
+        register(bool, type_id=TypeId.BOOL, serializer=BooleanSerializer)
+        register(Int8Type, type_id=TypeId.INT8, serializer=ByteSerializer)
+        register(Int16Type, type_id=TypeId.INT16, serializer=Int16Serializer)
+        register(Int32Type, type_id=TypeId.INT32, serializer=Int32Serializer)
+        register(Int64Type, type_id=TypeId.INT64, serializer=Int64Serializer)
+        register(int, type_id=DYNAMIC_TYPE_ID, serializer=DynamicIntSerializer)
+        register(
+            Float32Type,
+            type_id=TypeId.FLOAT32,
+            serializer=FloatSerializer,
+        )
+        register(
+            Float64Type,
+            type_id=TypeId.FLOAT64,
+            serializer=DoubleSerializer,
+        )
+        register(float, type_id=DYNAMIC_TYPE_ID, 
serializer=DynamicFloatSerializer)
+        register(str, type_id=TypeId.STRING, serializer=StringSerializer)
+        # TODO(chaokunyang) DURATION DECIMAL
+        register(
+            datetime.datetime, type_id=TypeId.TIMESTAMP, 
serializer=TimestampSerializer
+        )
+        register(datetime.date, type_id=TypeId.LOCAL_DATE, 
serializer=DateSerializer)
+        register(bytes, type_id=TypeId.BINARY, serializer=BytesSerializer)
+        for itemsize, ftype, typeid in 
PyArraySerializer.typecode_dict.values():
+            register(
+                ftype,
+                type_id=typeid,
+                serializer=PyArraySerializer(self.fury, ftype, typeid),
+            )
+        register(
+            array.array, type_id=DYNAMIC_TYPE_ID, 
serializer=DynamicPyArraySerializer
+        )
+        if np:
+            # overwrite pyarray  with same type id.
+            # if pyarray are needed, one must annotate that value with 
XXXArrayType
+            # as a field of a struct.
+            for dtype, (
+                itemsize,
+                format,
+                ftype,
+                typeid,
+            ) in Numpy1DArraySerializer.dtypes_dict.items():
+                register(
+                    ftype,
+                    type_id=typeid,
+                    serializer=Numpy1DArraySerializer(self.fury, ftype, dtype),
+                )
+            register(np.ndarray, type_id=DYNAMIC_TYPE_ID, 
serializer=NDArraySerializer)
+        register(list, type_id=TypeId.LIST, serializer=ListSerializer)
+        register(set, type_id=TypeId.SET, serializer=SetSerializer)
+        register(dict, type_id=TypeId.MAP, serializer=MapSerializer)
+        try:
+            import pyarrow as pa
+            from pyfury.format.serializer import (
+                ArrowRecordBatchSerializer,
+                ArrowTableSerializer,
+            )
+
+            register(
+                pa.RecordBatch,
+                type_id=TypeId.ARROW_RECORD_BATCH,
+                serializer=ArrowRecordBatchSerializer,
+            )
+            register(
+                pa.Table, type_id=TypeId.ARROW_TABLE, 
serializer=ArrowTableSerializer
+            )
+        except Exception:
+            pass
+
+    def register_type(
+        self,
+        cls: Union[type, TypeVar],
+        *,
+        type_id: int = None,
+        namespace: str = None,
+        typename: str = None,
+        serializer=None,
+    ):
+        return self._register_type(
+            cls,
+            type_id=type_id,
+            namespace=namespace,
+            typename=typename,
+            serializer=serializer,
+        )
+
+    def _register_type(
+        self,
+        cls: Union[type, TypeVar],
+        *,
+        type_id: int = None,
+        namespace: str = None,
+        typename: str = None,
+        serializer=None,
+        internal=False,
+    ):
+        """Register class with given type id or typename. If typename is not 
None, it will be used for
+        cross-language serialization."""
+        if serializer is not None and not isinstance(serializer, Serializer):
+            try:
+                serializer = serializer(self.fury, cls)
+            except BaseException:
+                try:
+                    serializer = serializer(self.fury)
+                except BaseException:
+                    serializer = serializer()
+        n_params = len({typename, type_id, None}) - 1

Review Comment:
   ```suggestion
           n_params = len((typename, type_id, None)) - 1
   ```
   In CPython, both `tuple` and `list` use a freelists to speed up allocation 
and deallocation, whereas `set` and `dict` do not have this. Therefore, using a 
tuple or list is more appropriate if you need a temporary structure.



##########
python/pyfury/_serialization.pyx:
##########
@@ -247,608 +238,364 @@ cdef int32_t NOT_NULL_STRING_FLAG = NOT_NULL_VALUE_FLAG 
& 0b11111111 | \
 cdef int32_t SMALL_STRING_THRESHOLD = 16
 
 
-cdef class BufferObject:
-    """
-    Fury binary representation of an object.
-    Note: This class is used for zero-copy out-of-band serialization and 
shouldn't be
-    used for any other cases.
-    """
-
-    cpdef int32_t total_bytes(self):
-        """total size for serialized bytes of an object"""
-        raise NotImplementedError
-
-    cpdef write_to(self, Buffer buffer):
-        """Write serialized object to a buffer."""
-        raise NotImplementedError
-
-    cpdef Buffer to_buffer(self):
-        """Write serialized data as Buffer."""
-        raise NotImplementedError
-
-
 @cython.final
-cdef class BytesBufferObject(BufferObject):
-    cdef public bytes binary
-
-    def __init__(self, bytes binary):
-        self.binary = binary
-
-    cpdef inline int32_t total_bytes(self):
-        return len(self.binary)
-
-    cpdef inline write_to(self, Buffer buffer):
-        buffer.write_bytes(self.binary)
-
-    cpdef inline Buffer to_buffer(self):
-        return Buffer(self.binary)
-
+cdef class MetaStringBytes:
+    cdef public bytes data
+    cdef int16_t length
+    cdef public int8_t encoding
+    cdef public int64_t hashcode
+    cdef public int16_t dynamic_write_string_id
 
[email protected]
-cdef class _PickleStub:
-    pass
+    def __init__(self, data, hashcode):
+        self.data = data
+        self.length = len(data)
+        self.hashcode = hashcode
+        self.encoding = hashcode & 0xff
+        self.dynamic_write_string_id = DEFAULT_DYNAMIC_WRITE_STRING_ID
 
+    def __eq__(self, other):
+        return type(other) is MetaStringBytes and other.hashcode == 
self.hashcode
 
[email protected]
-cdef class PickleStrongCacheStub:
-    pass
+    def __hash__(self):
+        return self.hashcode
 
+    def decode(self, decoder):
+        return decoder.decode(self.data, Encoding(self.encoding))
 
[email protected]
-cdef class PickleCacheStub:
-    pass
+    def __repr__(self):
+        return f"MetaStringBytes(data={self.data}, hashcode={self.hashcode})"
 
 
 @cython.final
-cdef class ClassResolver:
+cdef class MetaStringResolver:
     cdef:
-        readonly Fury fury
-        dict _type_id_to_class  # Dict[int, type]
-        dict _type_id_to_serializer  # Dict[int, Serializer]
-        dict _type_id_and_cls_to_serializer  # Dict[Tuple[int, type], 
Serializer]
-        dict _type_tag_to_class_x_lang_map
-        int16_t _class_id_counter
-        set _used_classes_id
-
-        public list _registered_id2_class_info
-        vector[PyObject*] _c_registered_id2_class_info
-
-        # cls -> ClassInfo
-        flat_hash_map[uint64_t, PyObject*] _c_classes_info
-        # hash -> ClassInfo
-        flat_hash_map[int64_t, PyObject*] _c_hash_to_classinfo
-        # hash -> MetaStringBytes
-        flat_hash_map[int64_t, PyObject*] _c_hash_to_enum_string_bytes
-        flat_hash_map[pair[int64_t, int64_t], PyObject*] 
_c_hash_to_small_metastring_bytes
-        # classname MetaStringBytes address -> class
-        flat_hash_map[uint64_t, PyObject*] _c_str_bytes_to_class
-        # classname MetaStringBytes address -> str
-        flat_hash_map[uint64_t, PyObject*] _c_enum_str_to_str
-
         int16_t dynamic_write_string_id
-        vector[PyObject*] _c_dynamic_written_enum_string
-        vector[PyObject*] _c_dynamic_id_to_enum_string_vec
-        vector[PyObject*] _c_dynamic_id_to_classinfo_vec
-        Serializer _serializer
-
-        # hold objects to avoid gc, since flat_hash_map/vector doesn't
-        # hold python reference.
-        public dict _classes_info  # Dict[type, "ClassInfo"]
-        set _class_set
-        set _classname_set
+        vector[PyObject *] _c_dynamic_written_enum_string
+        vector[PyObject *] _c_dynamic_id_to_enum_string_vec
+        # hash -> MetaStringBytes
+        flat_hash_map[int64_t, PyObject *] _c_hash_to_metastr_bytes
+        flat_hash_map[pair[int64_t, int64_t], PyObject *] 
_c_hash_to_small_metastring_bytes
         set _enum_str_set
+        dict _metastr_to_metastr_bytes
 
-    def __init__(self, fury):
-        self.fury = fury
-        self._type_id_to_class = dict()
-        self._type_id_to_serializer = dict()
-        self._type_id_and_cls_to_serializer = dict()
-        self._type_tag_to_class_x_lang_map = dict()
-        self._class_id_counter = PICKLE_CACHE_CLASS_ID + 1
-        self._used_classes_id = set()
-        self._registered_id2_class_info = list()
-
-        self.dynamic_write_string_id = 0
-        self._serializer = None
-
-        self._classes_info = dict()
-        self._class_set = set()
-        self._classname_set = set()
+    def __init__(self):
         self._enum_str_set = set()
-
-    def initialize(self):
-        self.register_class(int, class_id=PYINT_CLASS_ID)
-        self.register_class(float, class_id=PYFLOAT_CLASS_ID)
-        self.register_class(bool, class_id=PYBOOL_CLASS_ID)
-        self.register_class(str, class_id=STRING_CLASS_ID)
-        self.register_class(_PickleStub, class_id=PICKLE_CLASS_ID)
-        self.register_class(PickleStrongCacheStub, 
class_id=PICKLE_STRONG_CACHE_CLASS_ID)
-        self.register_class(PickleCacheStub, class_id=PICKLE_CACHE_CLASS_ID)
-        self._add_default_serializers()
-
-    def register_serializer(self, cls: Union[type, TypeVar], serializer):
-        assert isinstance(cls, (type, TypeVar)), cls
-        type_id = serializer.get_xtype_id()
-        if type_id != NOT_SUPPORT_CROSS_LANGUAGE:
-            self._add_x_lang_serializer(cls, serializer=serializer)
-        else:
-            self.register_class(cls)
-            self._classes_info[cls].serializer = serializer
-
-    def register_class(self, cls: Union[type, TypeVar], *, class_id: int = 
None, type_tag: str = None):
-        """Register class with given type id or tag, if tag is not None, it 
will be used for
-         cross-language serialization."""
-        if type_tag is not None:
-            assert class_id is None, (f"Type tag {type_tag} has been set 
already, "
-                                      f"set class id at the same time is not 
allowed.")
-            self.register_serializer(
-                cls, ComplexObjectSerializer(self.fury, cls, type_tag)
-            )
-            return
-        classinfo = self._classes_info.get(cls)
-        if classinfo is None:
-            if isinstance(cls, TypeVar):
-                class_name_bytes = (cls.__module__ + "#" + 
cls.__name__).encode("utf-8")
-            else:
-                class_name_bytes = (cls.__module__ + "#" + cls.__qualname__) \
-                    .encode("utf-8")
-            class_id = class_id if class_id is not None else 
self._next_class_id()
-            assert class_id not in self._used_classes_id, (
-                self._used_classes_id,
-                self._classes_info,
-            )
-            classinfo = ClassInfo(
-                cls=cls, class_name_bytes=class_name_bytes, class_id=class_id
-            )
-            self._classes_info[cls] = classinfo
-            self._c_classes_info[<uintptr_t><PyObject*>cls] = 
<PyObject*>classinfo
-            if len(self._registered_id2_class_info) <= class_id:
-                self._registered_id2_class_info.extend(
-                    [None] * (class_id - len(self._registered_id2_class_info) 
+ 1)
-                )
-            self._registered_id2_class_info[class_id] = classinfo
-            self._c_registered_id2_class_info.resize(class_id + 1)
-            self._c_registered_id2_class_info[class_id] = <PyObject*>classinfo
-        else:
-            if classinfo.class_id == NO_CLASS_ID:
-                class_id = class_id if class_id is not None else 
self._next_class_id()
-                assert class_id not in self._used_classes_id, (
-                    self._used_classes_id,
-                    self._classes_info,
-                )
-                classinfo.class_id = class_id
-                if len(self._registered_id2_class_info) <= class_id:
-                    self._registered_id2_class_info.extend(
-                        [None] * (class_id - 
len(self._registered_id2_class_info) + 1)
-                    )
-                self._registered_id2_class_info[class_id] = classinfo
-                self._c_registered_id2_class_info.resize(class_id + 1)
-                self._c_registered_id2_class_info[class_id] = 
<PyObject*>classinfo
-            else:
-                if class_id is not None and classinfo.class_id != class_id:
-                    raise ValueError(
-                        f"Inconsistent class id {class_id} vs 
{classinfo.class_id} "
-                        f"for class {cls}"
-                    )
-
-    def _next_class_id(self):
-        class_id = self._class_id_counter = self._class_id_counter + 1
-        while class_id in self._used_classes_id:
-            class_id = self._class_id_counter = self._class_id_counter + 1
-        return class_id
-
-    def _add_serializer(
-            self,
-            cls: Union[type, TypeVar],
-            serializer=None,
-            serializer_cls=None):
-        if serializer_cls:
-            serializer = serializer_cls(self.fury, cls)
-        self.register_serializer(cls, serializer)
-
-    def _add_x_lang_serializer(self,
-                               cls: Union[type, TypeVar],
-                               serializer=None,
-                               serializer_cls=None):
-        if serializer_cls:
-            serializer = serializer_cls(self.fury, cls)
-        type_id = serializer.get_xtype_id()
-
-        assert type_id != NOT_SUPPORT_CROSS_LANGUAGE
-        self._type_id_and_cls_to_serializer[(type_id, cls)] = serializer
-        self.register_class(cls)
-        classinfo = self._classes_info[cls]
-        classinfo.serializer = serializer
-        if type_id == FuryType.FURY_TYPE_TAG.value:
-            type_tag = serializer.get_xtype_tag()
-            assert type(type_tag) is str
-            assert type_tag not in self._type_tag_to_class_x_lang_map
-            classinfo.type_tag_bytes = 
MetaStringBytes(type_tag.encode("utf-8"))
-            self._type_tag_to_class_x_lang_map[type_tag] = cls
-        else:
-            self._type_id_to_serializer[type_id] = serializer
-            if type_id > NOT_SUPPORT_CROSS_LANGUAGE:
-                self._type_id_to_class[type_id] = cls
-
-    def _add_default_serializers(self):
-        self._add_x_lang_serializer(int, serializer_cls=ByteSerializer)
-        self._add_x_lang_serializer(int, serializer_cls=Int16Serializer)
-        self._add_x_lang_serializer(int, serializer_cls=Int32Serializer)
-        self._add_x_lang_serializer(int, serializer_cls=Int64Serializer)
-        self._add_x_lang_serializer(float, serializer_cls=FloatSerializer)
-        self._add_x_lang_serializer(float, serializer_cls=DoubleSerializer)
-        self._add_serializer(type(None), serializer_cls=NoneSerializer)
-        self._add_serializer(bool, serializer_cls=BooleanSerializer)
-        self._add_serializer(Int8Type, serializer_cls=ByteSerializer)
-        self._add_serializer(Int16Type, serializer_cls=Int16Serializer)
-        self._add_serializer(Int32Type, serializer_cls=Int32Serializer)
-        self._add_serializer(Int64Type, serializer_cls=Int64Serializer)
-        self._add_serializer(Float32Type, serializer_cls=FloatSerializer)
-        self._add_serializer(Float64Type, serializer_cls=DoubleSerializer)
-        self._add_serializer(str, serializer_cls=StringSerializer)
-        self._add_serializer(datetime.date, serializer_cls=DateSerializer)
-        self._add_serializer(
-            datetime.datetime, serializer_cls=TimestampSerializer
-        )
-        self._add_serializer(bytes, serializer_cls=BytesSerializer)
-        self._add_serializer(list, serializer_cls=ListSerializer)
-        self._add_serializer(tuple, serializer_cls=TupleSerializer)
-        self._add_serializer(dict, serializer_cls=MapSerializer)
-        self._add_serializer(set, serializer_cls=SetSerializer)
-        self._add_serializer(enum.Enum, serializer_cls=EnumSerializer)
-        self._add_serializer(slice, serializer_cls=SliceSerializer)
-        from pyfury import PickleCacheSerializer, PickleStrongCacheSerializer
-
-        self._add_serializer(PickleStrongCacheStub,
-                             serializer=PickleStrongCacheSerializer(self.fury))
-        self._add_serializer(PickleCacheStub,
-                             serializer=PickleCacheSerializer(self.fury))
-
-        try:
-            import pyarrow as pa
-            from pyfury.format.serializer import (
-                ArrowRecordBatchSerializer,
-                ArrowTableSerializer,
-            )
-
-            self._add_serializer(
-                pa.RecordBatch, serializer_cls=ArrowRecordBatchSerializer
-            )
-            self._add_serializer(pa.Table, serializer_cls=ArrowTableSerializer)
-        except Exception:
-            pass
-        for typecode in PyArraySerializer.typecode_dict.keys():
-            self._add_serializer(
-                array.array,
-                serializer=PyArraySerializer(self.fury, array.array, typecode),
-            )
-            self._add_serializer(
-                PyArraySerializer.typecodearray_type[typecode],
-                serializer=PyArraySerializer(self.fury, array.array, typecode),
-            )
-        if np:
-            for dtype in Numpy1DArraySerializer.dtypes_dict.keys():
-                self._add_serializer(
-                    np.ndarray,
-                    serializer=Numpy1DArraySerializer(self.fury, array.array, 
dtype),
-                )
-
-    cpdef inline Serializer get_serializer(self, cls=None, type_id=None, 
obj=None):
-        """
-        Returns
-        -------
-            Returns or create serializer for the provided class
-        """
-        assert cls is not None or type_id is not None or obj is not None
-
-        cdef Serializer serializer_
-        if obj is not None:
-            cls = type(obj)
-            if cls is int and 2**63 - 1 >= obj >= -(2**63):
-                type_id = FuryType.INT64.value
-            elif cls is float:
-                type_id = FuryType.DOUBLE.value
-            elif cls is array.array:
-                info = PyArraySerializer.typecode_dict.get(obj.typecode)
-                if info is not None:
-                    type_id = info[1]
-            elif np and cls is np.ndarray and obj.ndim == 1:
-                info = Numpy1DArraySerializer.dtypes_dict.get(obj.dtype)
-                if info:
-                    type_id = info[2]
-        if type_id is not None:
-            if cls is not None:
-                serializer_ = self._type_id_and_cls_to_serializer[(type_id, 
cls)]
-            else:
-                serializer_ = self._type_id_to_serializer[type_id]
-        else:
-            class_info = self._classes_info.get(cls)
-            if class_info is not None:
-                serializer_ = class_info.serializer
-            else:
-                self._add_serializer(cls, 
serializer=self.get_or_create_serializer(cls))
-                serializer_ = self._classes_info.get(cls).serializer
-        self._serializer = serializer_
-        return serializer_
-
-    cpdef inline Serializer get_or_create_serializer(self, cls):
-        return self.get_or_create_classinfo(cls).serializer
-
-    cpdef inline ClassInfo get_or_create_classinfo(self, cls):
-        cdef PyObject* classinfo_ptr = 
self._c_classes_info[<uintptr_t><PyObject*>cls]
-        cdef ClassInfo class_info
-        if classinfo_ptr != NULL:
-            class_info = <object>classinfo_ptr
-            if class_info.serializer is not None:
-                return class_info
-            else:
-                class_info.serializer = self._create_serializer(cls)
-                return class_info
-        else:
-            serializer = self._create_serializer(cls)
-            if type(serializer) is PickleSerializer:
-                class_id = PICKLE_CLASS_ID
-            else:
-                class_id = NO_CLASS_ID
-            class_name_bytes = (cls.__module__ + "#" + 
cls.__qualname__).encode("utf-8")
-            class_info = ClassInfo(
-                cls=cls, class_name_bytes=class_name_bytes,
-                serializer=serializer, class_id=class_id
-            )
-            self._classes_info[cls] = class_info
-            self._c_classes_info[<uintptr_t><PyObject*>cls] = 
<PyObject*>class_info
-            return class_info
-
-    cdef _create_serializer(self, cls):
-        mro = cls.__mro__
-        classinfo_ = self._classes_info.get(cls)
-        for clz in mro:
-            class_info = self._classes_info.get(clz)
-            if (
-                    class_info
-                    and class_info.serializer
-                    and class_info.serializer.support_subclass()
-            ):
-                if classinfo_ is None or classinfo_.class_id == NO_CLASS_ID:
-                    logger.info("Class %s not registered", cls)
-                serializer = type(class_info.serializer)(self.fury, cls)
-                break
-        else:
-            if dataclasses.is_dataclass(cls):
-                if classinfo_ is None or classinfo_.class_id == NO_CLASS_ID:
-                    logger.info("Class %s not registered", cls)
-                from pyfury import DataClassSerializer
-
-                serializer = DataClassSerializer(self.fury, cls)
-            else:
-                serializer = PickleSerializer(self.fury, cls)
-        return serializer
-
-    cpdef inline write_classinfo(self, Buffer buffer, ClassInfo classinfo):
-        cdef int32_t class_id = classinfo.class_id
-        if class_id != NO_CLASS_ID:
-            buffer.write_varint32((class_id << 1))
-            return
-        buffer.write_varint32(1)
-        self._write_enum_string_bytes(buffer, classinfo.class_name_bytes)
-
-    cpdef inline ClassInfo read_classinfo(self, Buffer buffer):
-        cdef int32_t h1 = buffer.read_varint32()
-        cdef int32_t class_id = h1 >> 1
-        cdef ClassInfo classinfo
-        cdef PyObject* classinfo_ptr
-        # registered class id are greater than `NO_CLASS_ID`.
-        if h1 & 0b1 == 0:
-            assert class_id >= 0, class_id
-            classinfo_ptr = self._c_registered_id2_class_info[class_id]
-            if classinfo_ptr == NULL:
-                raise ValueError(f"Unexpected class_id {class_id} "
-                                 f"{self._registered_id2_class_info}")
-            classinfo = <ClassInfo>classinfo_ptr
-            if classinfo.serializer is None:
-                classinfo.serializer = self._create_serializer(classinfo.cls)
-            return classinfo
-        cdef int32_t header = buffer.read_varint32()
-        cdef int32_t length = header >> 1
-        if header & 0b1 != 0:
-            return <ClassInfo>self._c_dynamic_id_to_classinfo_vec[length - 1]
-        cdef int64_t class_name_bytes_hash = buffer.read_int64()
-        cdef int32_t reader_index = buffer.reader_index
-        buffer.check_bound(reader_index, length)
-        buffer.reader_index = reader_index + length
-        classinfo_ptr = self._c_hash_to_classinfo[class_name_bytes_hash]
-        if classinfo_ptr != NULL:
-            self._c_dynamic_id_to_classinfo_vec.push_back(classinfo_ptr)
-            return <ClassInfo>classinfo_ptr
-        cdef bytes classname_bytes = buffer.get_bytes(reader_index, length)
-        cdef str full_class_name = classname_bytes.decode(encoding="utf-8")
-        cls = load_class(full_class_name)
-        classinfo = self.get_or_create_classinfo(cls)
-        classinfo_ptr = <PyObject*>classinfo
-        self._c_hash_to_classinfo[class_name_bytes_hash] = classinfo_ptr
-        self._c_dynamic_id_to_classinfo_vec.push_back(classinfo_ptr)
-        return classinfo
-
-    cdef inline _write_enum_string_bytes(
-            self, Buffer buffer, MetaStringBytes enum_string_bytes):
-        cdef int16_t dynamic_class_id = 
enum_string_bytes.dynamic_write_string_id
-        cdef int32_t length = enum_string_bytes.length
-        if dynamic_class_id == DEFAULT_DYNAMIC_WRITE_STRING_ID:
-            dynamic_class_id = self.dynamic_write_string_id
-            enum_string_bytes.dynamic_write_string_id = dynamic_class_id
+        self._metastr_to_metastr_bytes = dict()
+
+    cpdef inline write_meta_string_bytes(
+            self, Buffer buffer, MetaStringBytes metastr_bytes):
+        cdef int16_t dynamic_type_id = metastr_bytes.dynamic_write_string_id
+        cdef int32_t length = metastr_bytes.length
+        if dynamic_type_id == DEFAULT_DYNAMIC_WRITE_STRING_ID:
+            dynamic_type_id = self.dynamic_write_string_id
+            metastr_bytes.dynamic_write_string_id = dynamic_type_id
             self.dynamic_write_string_id += 1
-            
self._c_dynamic_written_enum_string.push_back(<PyObject*>enum_string_bytes)
-            buffer.write_varint32(length << 1)
+            self._c_dynamic_written_enum_string.push_back(<PyObject *> 
metastr_bytes)
+            buffer.write_varuint32(length << 1)
             if length <= SMALL_STRING_THRESHOLD:
-                buffer.write_int8(Encoding.UTF_8.value)
+                buffer.write_int8(metastr_bytes.encoding)
             else:
-                buffer.write_int64(enum_string_bytes.hashcode)
-            buffer.write_bytes(enum_string_bytes.data)
+                buffer.write_int64(metastr_bytes.hashcode)
+            buffer.write_bytes(metastr_bytes.data)
         else:
-            buffer.write_varint32(((dynamic_class_id + 1) << 1) | 1)
+            buffer.write_varuint32(((dynamic_type_id + 1) << 1) | 1)
 
-    cdef inline MetaStringBytes _read_enum_string_bytes(self, Buffer buffer):
-        cdef int32_t header = buffer.read_varint32()
+    cpdef inline MetaStringBytes read_meta_string_bytes(self, Buffer buffer):
+        cdef int32_t header = buffer.read_varuint32()
         cdef int32_t length = header >> 1
         if header & 0b1 != 0:
-            return 
<MetaStringBytes>self._c_dynamic_id_to_enum_string_vec[length - 1]
+            return <MetaStringBytes> 
self._c_dynamic_id_to_enum_string_vec[length - 1]
         cdef int64_t v1 = 0, v2 = 0, hashcode
-        cdef PyObject* enum_str_ptr
+        cdef PyObject * enum_str_ptr
         cdef int32_t reader_index
+        cdef encoding = 0
         if length <= SMALL_STRING_THRESHOLD:
-            # TODO(chaokunyang) support metastring encoding
-            buffer.read_int8()
+            encoding = buffer.read_int8()
             if length <= 8:
                 v1 = buffer.read_bytes_as_int64(length)
             else:
                 v1 = buffer.read_int64()
                 v2 = buffer.read_bytes_as_int64(length - 8)
-            hashcode = v1 * 31 + v2
+            hashcode = ((v1 * 31 + v2) >> 8 << 8) | encoding
             enum_str_ptr = 
self._c_hash_to_small_metastring_bytes[pair[int64_t, int64_t](v1, v2)]
             if enum_str_ptr == NULL:
                 reader_index = buffer.reader_index
                 str_bytes = buffer.get_bytes(reader_index - length, length)
                 enum_str = MetaStringBytes(str_bytes, hashcode=hashcode)
                 self._enum_str_set.add(enum_str)
-                enum_str_ptr = <PyObject*>enum_str
+                enum_str_ptr = <PyObject *> enum_str
                 self._c_hash_to_small_metastring_bytes[pair[int64_t, 
int64_t](v1, v2)] = enum_str_ptr
         else:
             hashcode = buffer.read_int64()
             reader_index = buffer.reader_index
             buffer.check_bound(reader_index, length)
             buffer.reader_index = reader_index + length
-            enum_str_ptr = self._c_hash_to_enum_string_bytes[hashcode]
+            enum_str_ptr = self._c_hash_to_metastr_bytes[hashcode]
             if enum_str_ptr == NULL:
                 str_bytes = buffer.get_bytes(reader_index, length)
                 enum_str = MetaStringBytes(str_bytes, hashcode=hashcode)
                 self._enum_str_set.add(enum_str)
-                enum_str_ptr = <PyObject*>enum_str
-                self._c_hash_to_enum_string_bytes[hashcode] = enum_str_ptr
+                enum_str_ptr = <PyObject *> enum_str
+                self._c_hash_to_metastr_bytes[hashcode] = enum_str_ptr
         self._c_dynamic_id_to_enum_string_vec.push_back(enum_str_ptr)
-        return <MetaStringBytes>enum_str_ptr
-
-    cpdef inline xwrite_class(self, Buffer buffer, cls):
-        cdef PyObject* classinfo_ptr = 
self._c_classes_info[<uintptr_t><PyObject*>cls]
-        assert classinfo_ptr != NULL
-        cdef MetaStringBytes class_name_bytes = 
(<object>classinfo_ptr).class_name_bytes
-        self._write_enum_string_bytes(buffer, class_name_bytes)
-
-    cpdef inline xwrite_type_tag(self, Buffer buffer, cls):
-        cdef PyObject* classinfo_ptr = 
self._c_classes_info[<uintptr_t><PyObject*>cls]
-        assert classinfo_ptr != NULL
-        cdef MetaStringBytes type_tag_bytes = 
(<object>classinfo_ptr).type_tag_bytes
-        self._write_enum_string_bytes(buffer, type_tag_bytes)
-
-    cpdef inline read_class_by_type_tag(self, Buffer buffer):
-        tag = self.xread_classname(buffer)
-        return self._type_tag_to_class_x_lang_map[tag]
-
-    cpdef inline xread_class(self, Buffer buffer):
-        cdef MetaStringBytes str_bytes = self._read_enum_string_bytes(buffer)
-        cdef uint64_t object_id = <uintptr_t><PyObject*>str_bytes
-        cdef PyObject* cls_ptr = self._c_str_bytes_to_class[object_id]
-        if cls_ptr != NULL:
-            return <object>cls_ptr
-        cdef str full_class_name = str_bytes.data.decode(encoding="utf-8")
-        cls = load_class(full_class_name)
-        self._c_str_bytes_to_class[object_id] = <PyObject*>cls
-        self._class_set.add(cls)
-        return cls
-
-    cpdef inline str xread_classname(self, Buffer buffer):
-        cdef MetaStringBytes str_bytes = self._read_enum_string_bytes(buffer)
-        cdef uint64_t object_id = <uintptr_t><PyObject*>str_bytes
-        cdef PyObject* classname_ptr = self._c_enum_str_to_str[object_id]
-        if classname_ptr != NULL:
-            return <object>classname_ptr
-        cdef str full_class_name = str_bytes.data.decode(encoding="utf-8")
-        self._c_enum_str_to_str[object_id] = <PyObject*>full_class_name
-        self._classname_set.add(full_class_name)
-        return full_class_name
-
-    cpdef inline get_class_by_type_id(self, int32_t type_id):
-        return self._type_id_to_class[type_id]
+        return <MetaStringBytes> enum_str_ptr
 
-    cpdef inline reset(self):
-        self.reset_write()
-        self.reset_read()
+    def get_metastr_bytes(self, metastr):
+        metastr_bytes = self._metastr_to_metastr_bytes.get(metastr)
+        if metastr_bytes is not None:
+            return metastr_bytes
+        cdef int64_t v1 = 0, v2 = 0, hashcode
+        length = len(metastr.encoded_data)
+        if length <= SMALL_STRING_THRESHOLD:
+            data_buf = Buffer(metastr.encoded_data)
+            if length <= 8:
+                v1 = data_buf.read_bytes_as_int64(length)
+            else:
+                v1 = data_buf.read_int64()
+                v2 = data_buf.read_bytes_as_int64(length - 8)
+            value_hash = ((v1 * 31 + v2) >> 8 << 8) | metastr.encoding.value
+        else:
+            value_hash = mmh3.hash_buffer(metastr.encoded_data, seed=47)[0]
+            value_hash = value_hash >> 8 << 8
+            value_hash |= metastr.encoding.value & 0xFF
+        self._metastr_to_metastr_bytes[metastr] = metastr_bytes = 
MetaStringBytes(metastr.encoded_data, value_hash)
+        return metastr_bytes
 
     cpdef inline reset_read(self):
         self._c_dynamic_id_to_enum_string_vec.clear()
-        self._c_dynamic_id_to_classinfo_vec.clear()
 
     cpdef inline reset_write(self):
         if self.dynamic_write_string_id != 0:
             self.dynamic_write_string_id = 0
             for ptr in self._c_dynamic_written_enum_string:
-                (<MetaStringBytes>ptr).dynamic_write_string_id = \
+                (<MetaStringBytes> ptr).dynamic_write_string_id = \
                     DEFAULT_DYNAMIC_WRITE_STRING_ID
             self._c_dynamic_written_enum_string.clear()
 
 
[email protected]
-cdef class MetaStringBytes:
-    cdef bytes data
-    cdef int16_t length
-    cdef int64_t hashcode
-    cdef int16_t dynamic_write_string_id
-
-    def __init__(self, data, hashcode=None):
-        self.data = data
-        self.length = len(data)
-        if hashcode is None:
-            hashcodes = mmh3.hash_buffer(data, 47)
-            hashcode = hashcodes[0]
-            assert isinstance(hashcode, int)
-            # FIXME: why using & 0xffffffffffffff00 overflow in cython
-            hashcode = (hashcode >> 8) << 8
-        self.hashcode = hashcode
-        self.dynamic_write_string_id = DEFAULT_DYNAMIC_WRITE_STRING_ID
-
-    def __eq__(self, other):
-        return type(other) is MetaStringBytes and other.hashcode == 
self.hashcode
-
-    def __hash__(self):
-        return self.hashcode
-
-
 @cython.final
 cdef class ClassInfo:
+    """
+    If dynamic_type is true, the serializer will be a dynamic typed serializer
+    and it will write type info when writing the data.
+    In such cases, the `write_classinfo` should not write typeinfo.
+    In general, if we have 4 type for one class, we will have 5 serializers.
+    For example, we have int8/16/32/64/128 for python `int` type, then we have 
6 serializers
+    for python `int`: `Int8/1632/64/128Serializer` for `int8/16/32/64/128` 
each, and another
+    `IntSerializer` for `int` which will dispatch to different 
`int8/16/32/64/128` type
+    according the actual value.
+    We do not get the acutal type here, because it will introduce extra 
computing.
+    For example, we have want to get actual `Int8/16/32/64Serializer`, we must 
check and
+    extract the actutal here which will introduce cost, and we will do same 
thing again
+    when serializing the actual data.
+    """
     cdef public object cls
-    cdef public int16_t class_id
+    cdef public int16_t type_id
     cdef public Serializer serializer
-    cdef public MetaStringBytes class_name_bytes
-    cdef public MetaStringBytes type_tag_bytes
+    cdef public MetaStringBytes namespace_bytes
+    cdef public MetaStringBytes typename_bytes
+    cdef public c_bool dynamic_type
 
     def __init__(
             self,
             cls: Union[type, TypeVar] = None,
-            class_id: int = NO_CLASS_ID,
+            type_id: int = NO_CLASS_ID,
             serializer: Serializer = None,
-            class_name_bytes: bytes = None,
-            type_tag_bytes: bytes = None,
+            namespace_bytes: MetaStringBytes = None,
+            typename_bytes: MetaStringBytes = None,
+            dynamic_type: bool = False,
     ):
         self.cls = cls
-        self.class_id = class_id
+        self.type_id = type_id
         self.serializer = serializer
-        self.class_name_bytes = MetaStringBytes(class_name_bytes)
-        if type_tag_bytes is None:
-            self.type_tag_bytes = None
-        else:
-            self.type_tag_bytes = MetaStringBytes(type_tag_bytes)
+        self.namespace_bytes = namespace_bytes
+        self.typename_bytes = typename_bytes
+        self.dynamic_type = dynamic_type
 
     def __repr__(self):
-        return f"ClassInfo(cls={self.cls}, class_id={self.class_id}, " \
+        return f"ClassInfo(cls={self.cls}, type_id={self.type_id}, " \
                f"serializer={self.serializer})"
 
 
[email protected]
+cdef class ClassResolver:
+    cdef:
+        readonly Fury fury
+        readonly MetaStringResolver metastring_resolver
+        object _resolver
+        vector[PyObject *] _c_registered_id_to_class_info
+        # cls -> ClassInfo
+        flat_hash_map[uint64_t, PyObject *] _c_classes_info
+        # hash -> ClassInfo
+        flat_hash_map[pair[int64_t, int64_t], PyObject *] 
_c_meta_hash_to_classinfo
+        MetaStringResolver meta_string_resolver
+
+    def __init__(self, fury):
+        self.fury = fury
+        self.metastring_resolver = fury.metastring_resolver
+        from pyfury._registry import ClassResolver
+        self._resolver = ClassResolver(fury)
+
+    def initialize(self):
+        self._resolver.initialize()
+        for classinfo in self._resolver._classes_info.values():
+            self._populate_typeinfo(classinfo)
+
+    def register_type(
+            self,
+            cls: Union[type, TypeVar],
+            *,
+            type_id: int = None,
+            namespace: str = None,
+            typename: str = None,
+            serializer=None,
+    ):
+        typeinfo = self._resolver.register_type(
+            cls,
+            type_id=type_id,
+            namespace=namespace,
+            typename=typename,
+            serializer=serializer,
+        )
+        self._populate_typeinfo(typeinfo)
+
+    cdef _populate_typeinfo(self, typeinfo):
+        type_id = typeinfo.type_id
+        if type_id >= self._c_registered_id_to_class_info.size():
+            self._c_registered_id_to_class_info.resize(type_id * 2, NULL)
+        if type_id > 0 and (self.fury.language == Language.PYTHON or not 
IsNamespacedType(type_id)):
+            self._c_registered_id_to_class_info[type_id] = <PyObject *> 
typeinfo
+        self._c_classes_info[<uintptr_t> <PyObject *> typeinfo.cls] = 
<PyObject *> typeinfo
+        if typeinfo.typename_bytes is not None:
+            self._load_bytes_to_classinfo(type_id, typeinfo.namespace_bytes, 
typeinfo.typename_bytes)
+
+    def register_serializer(self, cls: Union[type, TypeVar], serializer):
+        classinfo1 = self._resolver.get_classinfo(cls)
+        self._resolver.register_serializer(cls, serializer)
+        classinfo2 = self._resolver.get_classinfo(cls)
+        if classinfo1.type_id != classinfo2.type_id:
+            self._c_registered_id_to_class_info[classinfo1.type_id] = NULL
+            self._populate_typeinfo(classinfo2)
+
+    cpdef inline Serializer get_serializer(self, cls):
+        """
+        Returns
+        -------
+            Returns or create serializer for the provided class
+        """
+        return self.get_classinfo(cls).serializer
+
+    cpdef inline ClassInfo get_classinfo(self, cls, create=True):
+        cdef PyObject * classinfo_ptr = self._c_classes_info[<uintptr_t> 
<PyObject *> cls]
+        cdef ClassInfo class_info
+        if classinfo_ptr != NULL:
+            class_info = <object> classinfo_ptr
+            if class_info.serializer is not None:
+                return class_info
+            else:
+                class_info.serializer = self._resolver._create_serializer(cls)
+                return class_info
+        elif not create:
+            return

Review Comment:
   ```suggestion
               return None
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to