Pardon the confusing title but I am doing something truly cursed.
I have a large project written in Python that I want to write a GUI in Swift for. I'm able to use PythonKit to call my Python code from Swift just fine.
The only problem is that the Python program deals with laying out the UI elements since they form a directed graph and the layout algorithm is non-trivial.
The layout algorithm needs to know the size of each node in the graph to deal with overlapping nodes, but only the GUI knows what the rendered size of each node will be.
Therefore, I want to pass a callback written in Swift to the layout function that is written in Python.
I've pared down the code to be able to minimally reproduce the behavior.
let nodeSizeFn: @convention(c) (UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? = { _ in
return PyInt_FromLong(30)
}
let nodeSizeFnPtr = unsafeBitCast(nodeSizeFn, to: UnsafeMutableRawPointer.self)
let nodeSizeFnAddr = UInt(bitPattern: nodeSizeFnPtr)
private let ctypes = Python.import("ctypes")
let sizefn = ctypes.CFUNCTYPE(ctypes.py_object)(nodeSizeFnAddr)
let (xs, ys, ws, hs) = graph.layout(sizefn).tuple4
This code segfaults in the call to PyInt_FromLong
in the callback. From using LLDB, it seems that the SMALL_INT
singleton/global object/static object (in CPython parlance) is null in the callback. I'm not sure how this is possible since PythonKit calls Py_Initialize
and a similar call to PyInt_FromLong
outside of the callback works fine.
Any and all help is appreciated. Thank you.