All of these issues can be abstracted in a macro for defining foreign structures. This is explained in the following message:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2009-May/003475.html
Marc
Geez, I so wish I'd found that one about one year ago, when I was trying to do the same thing! :)
My best effort attempt (don't use it! it never got out of playground/experimental stage) was here:
https://github.com/euccastro/gambit-SDL2/blob/master/ffi-macro.scm
That one also tries to overcome the following issue, which Marc's macro (perhaps wisely) leaves alone:
;; IMPORTANT NOTE: the foreign pointer returned by s2-coordinates-ref ;; is a pointer to a C struct within another C struct (the ;; "container"). The foreign pointer is only valid as long as the ;; container is allocated. Be wary that in the case of a C structure ;; allocated from Scheme, such as with a call to alloc-s2, the garbage ;; collector could reclaim the structure as soon as the foreign ;; pointer to it is dropped.
I tried to solve that problem by keeping a table of references with weak keys corresponding to contained/child structs and strong values corresponding to container/parent values.
The big problem was how to make the references table unique since it was defined in macro-defining code, i.e., which was meant to be included, not loaded. I suppose the cleaner solution would have been to make a separate ffi library to `load`. I don't remember why I didn't just do this. The hacky approach in that file (checking for the current type of the symbol) seemed to work, but I guess that relies on undocumented behavior.
In retrospect, that would have been made so much easier if you could assign an arbitrary Scheme reference to a foreign pointer. I think that would address a genuine need: in general, ffi pointers may point to objects that 'depend' on other objects managed in the scheme world (probably other ffi pointers), in such a way that it makes sense to keep the dependencies alive while the pointer is in the scheme world. Something like ___set_data_rc, but you can't use this function since that messes with memory in the vicinity of the object pointed to; most often, this memory belongs to the container/parent struct. So it would need to be something like a Scheme call
(set-foreign-reference! pointer dependency)
that would set a ___SCMOBJ field in the foreign object itself. A getter is not needed for this use case, but maybe it would enable other uses (?).
Alternatively, there could be a different type of foreign object that has this functionality, so applications that don't use it won't incur the space cost of the additional pointer.