@@ -20,6 +20,9 @@ static PyObject * record_new_items_iter(PyObject *);
2020static ApgRecordObject * free_list [ApgRecord_MAXSAVESIZE ];
2121static int numfree [ApgRecord_MAXSAVESIZE ];
2222
23+ static PyObject * record_reconstruct_obj ;
24+ static PyObject * record_desc_reconstruct_obj ;
25+
2326static size_t MAX_RECORD_SIZE = (
2427 ((size_t )PY_SSIZE_T_MAX - sizeof (ApgRecordObject ) - sizeof (PyObject * ))
2528 / sizeof (PyObject * )
@@ -575,14 +578,14 @@ record_repr(ApgRecordObject *v)
575578
576579
577580static PyObject *
578- record_values (PyObject * o , PyObject * args )
581+ record_values (PyObject * o , PyObject * Py_UNUSED ( unused ) )
579582{
580583 return record_iter (o );
581584}
582585
583586
584587static PyObject *
585- record_keys (PyObject * o , PyObject * args )
588+ record_keys (PyObject * o , PyObject * Py_UNUSED ( unused ) )
586589{
587590 if (!ApgRecord_Check (o )) {
588591 PyErr_BadInternalCall ();
@@ -594,7 +597,7 @@ record_keys(PyObject *o, PyObject *args)
594597
595598
596599static PyObject *
597- record_items (PyObject * o , PyObject * args )
600+ record_items (PyObject * o , PyObject * Py_UNUSED ( unused ) )
598601{
599602 if (!ApgRecord_Check (o )) {
600603 PyErr_BadInternalCall ();
@@ -658,11 +661,69 @@ static PyMappingMethods record_as_mapping = {
658661};
659662
660663
664+ static PyObject *
665+ record_reduce (ApgRecordObject * o , PyObject * Py_UNUSED (unused ))
666+ {
667+ PyObject * value = PyTuple_New (2 );
668+ if (value == NULL ) {
669+ return NULL ;
670+ }
671+ Py_ssize_t len = Py_SIZE (o );
672+ PyObject * state = PyTuple_New (1 + len );
673+ if (state == NULL ) {
674+ Py_DECREF (value );
675+ return NULL ;
676+ }
677+ PyTuple_SET_ITEM (value , 0 , record_reconstruct_obj );
678+ Py_INCREF (record_reconstruct_obj );
679+ PyTuple_SET_ITEM (value , 1 , state );
680+ PyTuple_SET_ITEM (state , 0 , (PyObject * )o -> desc );
681+ Py_INCREF (o -> desc );
682+ for (Py_ssize_t i = 0 ; i < len ; i ++ ) {
683+ PyObject * item = ApgRecord_GET_ITEM (o , i );
684+ PyTuple_SET_ITEM (state , i + 1 , item );
685+ Py_INCREF (item );
686+ }
687+ return value ;
688+ }
689+
690+ static PyObject *
691+ record_reconstruct (PyObject * Py_UNUSED (unused ), PyObject * args )
692+ {
693+ if (!PyTuple_CheckExact (args )) {
694+ return NULL ;
695+ }
696+ Py_ssize_t len = PyTuple_GET_SIZE (args );
697+ if (len < 2 ) {
698+ return NULL ;
699+ }
700+ len -- ;
701+ ApgRecordDescObject * desc = (ApgRecordDescObject * )PyTuple_GET_ITEM (args , 0 );
702+ if (!ApgRecordDesc_CheckExact (desc )) {
703+ return NULL ;
704+ }
705+ if (PyObject_Length (desc -> mapping ) != len ) {
706+ return NULL ;
707+ }
708+ PyObject * record = ApgRecord_New (& ApgRecord_Type , (PyObject * )desc , len );
709+ if (record == NULL ) {
710+ return NULL ;
711+ }
712+ for (Py_ssize_t i = 0 ; i < len ; i ++ ) {
713+ PyObject * item = PyTuple_GET_ITEM (args , i + 1 );
714+ ApgRecord_SET_ITEM (record , i , item );
715+ Py_INCREF (item );
716+ }
717+ return record ;
718+ }
719+
661720static PyMethodDef record_methods [] = {
662721 {"values" , (PyCFunction )record_values , METH_NOARGS },
663722 {"keys" , (PyCFunction )record_keys , METH_NOARGS },
664723 {"items" , (PyCFunction )record_items , METH_NOARGS },
665724 {"get" , (PyCFunction )record_get , METH_VARARGS },
725+ {"__reduce__" , (PyCFunction )record_reduce , METH_NOARGS },
726+ {"__reconstruct__" , (PyCFunction )record_reconstruct , METH_VARARGS | METH_STATIC },
666727 {NULL , NULL } /* sentinel */
667728};
668729
@@ -942,29 +1003,6 @@ record_new_items_iter(PyObject *seq)
9421003}
9431004
9441005
945- PyTypeObject *
946- ApgRecord_InitTypes (void )
947- {
948- if (PyType_Ready (& ApgRecord_Type ) < 0 ) {
949- return NULL ;
950- }
951-
952- if (PyType_Ready (& ApgRecordDesc_Type ) < 0 ) {
953- return NULL ;
954- }
955-
956- if (PyType_Ready (& ApgRecordIter_Type ) < 0 ) {
957- return NULL ;
958- }
959-
960- if (PyType_Ready (& ApgRecordItems_Type ) < 0 ) {
961- return NULL ;
962- }
963-
964- return & ApgRecord_Type ;
965- }
966-
967-
9681006/* ----------------- */
9691007
9701008
@@ -987,15 +1025,54 @@ record_desc_traverse(ApgRecordDescObject *o, visitproc visit, void *arg)
9871025}
9881026
9891027
1028+ static PyObject * record_desc_reduce (ApgRecordDescObject * o , PyObject * Py_UNUSED (unused ))
1029+ {
1030+ PyObject * value = PyTuple_New (2 );
1031+ if (value == NULL ) {
1032+ return NULL ;
1033+ }
1034+ PyObject * state = PyTuple_New (2 );
1035+ if (state == NULL ) {
1036+ Py_DECREF (value );
1037+ return NULL ;
1038+ }
1039+ PyTuple_SET_ITEM (value , 0 , record_desc_reconstruct_obj );
1040+ Py_INCREF (record_desc_reconstruct_obj );
1041+ PyTuple_SET_ITEM (value , 1 , state );
1042+ PyTuple_SET_ITEM (state , 0 , o -> mapping );
1043+ Py_INCREF (o -> mapping );
1044+ PyTuple_SET_ITEM (state , 1 , o -> keys );
1045+ Py_INCREF (o -> keys );
1046+ return value ;
1047+ }
1048+
1049+
1050+ static PyObject * record_desc_reconstruct (PyObject * Py_UNUSED (unused ), PyObject * args )
1051+ {
1052+ if (PyTuple_GET_SIZE (args ) != 2 ) {
1053+ return NULL ;
1054+ }
1055+ return ApgRecordDesc_New (PyTuple_GET_ITEM (args , 0 ), PyTuple_GET_ITEM (args , 1 ));
1056+ }
1057+
1058+
1059+ static PyMethodDef record_desc_methods [] = {
1060+ {"__reduce__" , (PyCFunction )record_desc_reduce , METH_NOARGS },
1061+ {"__reconstruct__" , (PyCFunction )record_desc_reconstruct , METH_VARARGS | METH_STATIC },
1062+ {NULL , NULL } /* sentinel */
1063+ };
1064+
1065+
9901066PyTypeObject ApgRecordDesc_Type = {
9911067 PyVarObject_HEAD_INIT (NULL , 0 )
992- .tp_name = "RecordDescriptor" ,
1068+ .tp_name = "asyncpg.protocol.protocol. RecordDescriptor" ,
9931069 .tp_basicsize = sizeof (ApgRecordDescObject ),
9941070 .tp_dealloc = (destructor )record_desc_dealloc ,
9951071 .tp_getattro = PyObject_GenericGetAttr ,
9961072 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC ,
9971073 .tp_traverse = (traverseproc )record_desc_traverse ,
9981074 .tp_iter = PyObject_SelfIter ,
1075+ .tp_methods = record_desc_methods ,
9991076};
10001077
10011078
@@ -1023,3 +1100,41 @@ ApgRecordDesc_New(PyObject *mapping, PyObject *keys)
10231100 PyObject_GC_Track (o );
10241101 return (PyObject * ) o ;
10251102}
1103+
1104+
1105+ PyObject *
1106+ ApgRecord_InitTypes (void )
1107+ {
1108+ if (PyType_Ready (& ApgRecord_Type ) < 0 ) {
1109+ return NULL ;
1110+ }
1111+
1112+ if (PyType_Ready (& ApgRecordDesc_Type ) < 0 ) {
1113+ return NULL ;
1114+ }
1115+
1116+ if (PyType_Ready (& ApgRecordIter_Type ) < 0 ) {
1117+ return NULL ;
1118+ }
1119+
1120+ if (PyType_Ready (& ApgRecordItems_Type ) < 0 ) {
1121+ return NULL ;
1122+ }
1123+
1124+ record_reconstruct_obj = PyCFunction_New (
1125+ & record_methods [5 ], (PyObject * )& ApgRecord_Type
1126+ );
1127+ record_desc_reconstruct_obj = PyCFunction_New (
1128+ & record_desc_methods [1 ], (PyObject * )& ApgRecordDesc_Type
1129+ );
1130+
1131+ PyObject * types = PyTuple_New (2 );
1132+ if (types == NULL ) {
1133+ return NULL ;
1134+ }
1135+ PyTuple_SET_ITEM (types , 0 , (PyObject * )& ApgRecord_Type );
1136+ Py_INCREF (& ApgRecord_Type );
1137+ PyTuple_SET_ITEM (types , 1 , (PyObject * )& ApgRecordDesc_Type );
1138+ Py_INCREF (& ApgRecordDesc_Type );
1139+ return types ;
1140+ }
0 commit comments