@@ -10,29 +10,31 @@ enum class DataType {
1010    None,
1111    Int,
1212    Double,
13-     String
13+     String,
14+     PyObject
1415};
1516
1617typedef  struct  {
1718    PyObject_HEAD
1819    std::string name;
19-     std::variant<std::monostate, int64_t , double , std::string> data;
20+     std::variant<std::monostate, int64_t , double , std::string, PyObject* > data;
2021    DataType data_type;
2122} GraphNode;
2223
23- static  void  GraphNode_dealloc (GraphNode* self){
24-     self->name .~basic_string ();
25-     self->data .~decltype (self->data)();
26-     Py_TYPE (self)->tp_free (reinterpret_cast <PyTypeObject*>(self));
24+ static  void  GraphNode_dealloc (GraphNode* self) {
25+     if  (self->data_type  == DataType::PyObject) {
26+         Py_XDECREF (std::get<PyObject*>(self->data ));
27+     }
28+     Py_TYPE (self)->tp_free (reinterpret_cast <PyObject*>(self));
2729}
2830
29- static  PyObject* GraphNode_new (PyTypeObject* type, PyObject* args, PyObject* kwds){
30-     GraphNode* self;
31-     self = reinterpret_cast <GraphNode*>(type->tp_alloc (type,0 ));
31+ static  PyObject* GraphNode_new (PyTypeObject* type, PyObject* args, PyObject* kwds) {
32+     GraphNode* self = reinterpret_cast <GraphNode*>(type->tp_alloc (type, 0 ));
33+     if  (!self) return  NULL ;
34+ 
3235    new  (&self->name ) std::string ();
33-     new  (&self->data ) std::variant<std::monostate, int64_t , double , std::string>();
36+     new  (&self->data ) std::variant<std::monostate, int64_t , double , std::string, PyObject* >();
3437    self->data_type  = DataType::None;
35-     if  (!self) return  NULL ;
3638
3739    static  char * kwlist[] = { " name" " data" NULL  };
3840    const  char * name;
@@ -59,8 +61,9 @@ static PyObject* GraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwd
5961        self->data  = std::string (s);
6062        self->data_type  = DataType::String;
6163    } else  {
62-         PyErr_SetString (PyExc_TypeError, " data must be int, float, str, or None" 
63-         return  NULL ;
64+         self->data  = data;
65+         self->data_type  = DataType::PyObject;
66+         Py_INCREF (data);
6467    }
6568
6669    return  reinterpret_cast <PyObject*>(self);
@@ -82,15 +85,28 @@ static PyObject* GraphNode_str(GraphNode* self) {
8285        case  DataType::String:
8386            repr += " '" data ) + " '" 
8487            break ;
88+         case  DataType::PyObject: {
89+             PyObject* repr_obj = PyObject_Repr (std::get<PyObject*>(self->data ));
90+             if  (repr_obj) {
91+                 const  char * repr_cstr = PyUnicode_AsUTF8 (repr_obj);
92+                 repr += repr_cstr ? repr_cstr : " <unprintable>" 
93+                 Py_DECREF (repr_obj);
94+             } else  {
95+                 repr += " <error in repr>" 
96+             }
97+             break ;
98+         }
8599    }
100+ 
86101    repr += " )" 
87102    return  PyUnicode_FromString (repr.c_str ());
88103}
89104
90105static  PyObject* GraphNode_get (GraphNode* self, void  *closure) {
91-     if  (closure == (void *)" name" 
106+     const  char * attr = reinterpret_cast <const  char *>(closure);
107+     if  (strcmp (attr, " name" 0 ) {
92108        return  PyUnicode_FromString (self->name .c_str ());
93-     } else  if  (closure == ( void *) " data" 
109+     } else  if  (strcmp (attr,  " data" ) ==  0 ) {
94110        switch  (self->data_type ) {
95111            case  DataType::None:
96112                Py_RETURN_NONE;
@@ -100,25 +116,32 @@ static PyObject* GraphNode_get(GraphNode* self, void *closure) {
100116                return  PyFloat_FromDouble (std::get<double >(self->data ));
101117            case  DataType::String:
102118                return  PyUnicode_FromString (std::get<std::string>(self->data ).c_str ());
119+             case  DataType::PyObject:
120+                 Py_INCREF (std::get<PyObject*>(self->data ));
121+                 return  std::get<PyObject*>(self->data );
103122        }
104123    }
105124    Py_RETURN_NONE;
106125}
107126
108127static  int  GraphNode_set (GraphNode* self, PyObject *value, void  *closure) {
128+     const  char * attr = reinterpret_cast <const  char *>(closure);
109129    if  (!value) {
110130        PyErr_SetString (PyExc_ValueError, " Cannot delete attributes" 
111131        return  -1 ;
112132    }
113133
114-     if  (closure == ( void *) " name" 
134+     if  (strcmp (attr,  " name" ) ==  0 ) {
115135        if  (!PyUnicode_Check (value)) {
116136            PyErr_SetString (PyExc_TypeError, " name must be a string" 
117137            return  -1 ;
118138        }
119139        self->name  = PyUnicode_AsUTF8 (value);
120-     }
121-     else  if  (closure == (void *)" data" 
140+     } else  if  (strcmp (attr, " data" 0 ) {
141+         if  (self->data_type  == DataType::PyObject) {
142+             Py_XDECREF (std::get<PyObject*>(self->data ));
143+         }
144+ 
122145        if  (value == Py_None) {
123146            self->data  = std::monostate{};
124147            self->data_type  = DataType::None;
@@ -132,8 +155,9 @@ static int GraphNode_set(GraphNode* self, PyObject *value, void *closure) {
132155            self->data  = std::string (PyUnicode_AsUTF8 (value));
133156            self->data_type  = DataType::String;
134157        } else  {
135-             PyErr_SetString (PyExc_TypeError, " data must be int, float, str, or None" 
136-             return  -1 ;
158+             Py_INCREF (value);
159+             self->data  = value;
160+             self->data_type  = DataType::PyObject;
137161        }
138162    } else  {
139163        PyErr_SetString (PyExc_AttributeError, " Unknown attribute" 
0 commit comments