Skip to content

Commit 46cbd5f

Browse files
authored
Merge pull request #58 from benoitc/feature/shared-dict
Add SharedDict: process-scoped shared dictionaries
2 parents 19bc977 + d20db55 commit 46cbd5f

File tree

8 files changed

+2013
-7
lines changed

8 files changed

+2013
-7
lines changed

c_src/py_callback.c

Lines changed: 474 additions & 0 deletions
Large diffs are not rendered by default.

c_src/py_convert.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
/* Capsule name for channel references */
5353
#define CHANNEL_CAPSULE_NAME "erlang.channel_ref"
5454

55+
/* Capsule name for shared dict references */
56+
#define SHARED_DICT_CAPSULE_NAME "py_shared_dict"
57+
5558
/**
5659
* @brief PyCapsule destructor for channel references
5760
*
@@ -65,6 +68,19 @@ static void channel_capsule_destructor(PyObject *capsule) {
6568
}
6669
}
6770

71+
/**
72+
* @brief PyCapsule destructor for shared dict references
73+
*
74+
* Called when a PyCapsule wrapping a SharedDict resource is garbage collected.
75+
* Releases the resource reference that was kept when the capsule was created.
76+
*/
77+
static void shared_dict_capsule_destructor(PyObject *capsule) {
78+
void *ptr = PyCapsule_GetPointer(capsule, SHARED_DICT_CAPSULE_NAME);
79+
if (ptr != NULL) {
80+
enif_release_resource(ptr);
81+
}
82+
}
83+
6884
/* ============================================================================
6985
* Python to Erlang Conversion
7086
* ============================================================================ */
@@ -381,7 +397,16 @@ ERL_NIF_TERM py_to_term(ErlNifEnv *env, PyObject *obj) {
381397
py_channel_t *channel = (py_channel_t *)ptr;
382398
return enif_make_resource(env, channel);
383399
}
384-
/* Not a channel capsule, clear error and fall through */
400+
/* Not a channel capsule, clear error and try SharedDict */
401+
PyErr_Clear();
402+
403+
ptr = PyCapsule_GetPointer(obj, SHARED_DICT_CAPSULE_NAME);
404+
if (ptr != NULL) {
405+
/* This is a SharedDict reference capsule - convert back to resource term */
406+
py_shared_dict_t *sd = (py_shared_dict_t *)ptr;
407+
return enif_make_resource(env, sd);
408+
}
409+
/* Not a SharedDict capsule either, clear error and fall through */
385410
PyErr_Clear();
386411
}
387412

@@ -647,6 +672,21 @@ static PyObject *term_to_py(ErlNifEnv *env, ERL_NIF_TERM term) {
647672
return PyBuffer_from_resource(pybuf, pybuf);
648673
}
649674

675+
/* Check for shared dict resource - wrap in PyCapsule for Python access */
676+
py_shared_dict_t *shared_dict;
677+
if (enif_get_resource(env, term, PY_SHARED_DICT_RESOURCE_TYPE, (void **)&shared_dict)) {
678+
/* Create a PyCapsule wrapping the SharedDict pointer.
679+
* We increment the resource refcount so it stays valid while Python holds it.
680+
* The destructor will decrement it when the capsule is garbage collected. */
681+
enif_keep_resource(shared_dict);
682+
PyObject *capsule = PyCapsule_New(shared_dict, SHARED_DICT_CAPSULE_NAME, shared_dict_capsule_destructor);
683+
if (capsule == NULL) {
684+
enif_release_resource(shared_dict);
685+
return NULL;
686+
}
687+
return capsule;
688+
}
689+
650690
/* Check for reference - serialize to binary for round-trip.
651691
* IMPORTANT: This must come AFTER all resource checks, because NIF
652692
* resource terms also satisfy enif_is_ref() but should be handled

0 commit comments

Comments
 (0)