Mqx
Mqx•2mo ago

Best practice for passing Array of Objects from C++ to TS using FFI

Hey, what is the best way to pass an array of objects from C++ via DLL to TS? We are trying to write a Serial Library and we query a list of available ports and their information. Similar to the serialport.io node library. What would be the best way to pass all the available ports and their information to TS?
4 Replies
Mrcool 🇵🇸
Maybe you can find an example here https://github.com/aapoalas/libclang_deno
AapoAlas
AapoAlas•2mo ago
If it's the Deno/JS side doing the querying ("do you have available ports, and if so then which and how many?") and the C++/DLL side answering the question ("thank you for the question, I have 3 open ports; A, B, and C") then the way would usually be an API like this: 1. a native API that either takes a *uintptr_t and returns *OpenPort, or takes an **OpenPort and returns a uintptr_t. 2. a native API that takes an *OpenPort and uintptr_t, and deallocates the list of open ports. 3. any APIs you need for working with OpenPort objects. When the Deno/JS side asks the question, it'll pass the pointer as a parameter. The native side writes data through that pointer and returns the rest of the answer; this way you'd get the pointer to the first OpenPort in the list, and the number of OpenPort objects in the list. Then on Deno-side you just perform memory-offsets to find the rest of the objects in the list. Alternatively, you can wrap the list into an object itself. Your API would then be something like extern void getOpenPorts(*OpenPortsList); JS side allocates enough room to hold an OpenPortsList using an ArrayBuffer and passes the pointer to that to the DLL. The DLL then writes the necessary data through that pointer (the actual list pointer and length, probably). Besides that you'd still obviously need a destructor for OpenPortsList, and then all the public API functions for working with OpenPortsList, like OpenPortsList::getOpenPort(index) kind of things. In libclang_deno, you can find out-pointers like *uintptr_t and **OpenPort by searching for OUT in mod.ts; since the out-pointers are only ever needed temporarily for a single call, I reuse the same allocation all-over the place there. Hence, it's easy to see when it gets used. eg. this method sends an out-pointer OUT to getFileContents; the DLL method returns a pointer to the file contents char buffer and writes the length of the buffer into the OUT pointer; the result is read using the OUT_64 BigUint64Array view of the OUT memory. Naturally, a char buffer and an array of objects feel very far away from one another, but conceptually you can think of a char buffer as just an array of objects where the object type is char.
AapoAlas
AapoAlas•2mo ago
You may also be interested in my txx library built ontop of libclang_deno: it's not a very complete system as I kind of gave up on trying to understand C++ templates well enough to automatically translate eg. std::string and std::function into Deno FFI APIs, but it might be a pretty capable thing for auto-generating bindings and Deno-side interface classes for working with C++ FFI classes.
GitHub
GitHub - aapoalas/txx: Unsafe interop between Deno FFI and C++
Unsafe interop between Deno FFI and C++. Contribute to aapoalas/txx development by creating an account on GitHub.
jeff.hykin
jeff.hykin•2mo ago
If you just want a serial library, checkout the one recently posted by lucsoft in #showcase (rust based web serial). I've also got my own pure deno one https://github.com/jeff-hykin/deno_serial , but I need to refine the API and clean up before doing a 1.0 release
GitHub
GitHub - jeff-hykin/deno_serial: Serialport API for Deno.
Serialport API for Deno. Contribute to jeff-hykin/deno_serial development by creating an account on GitHub.

Did you find this page helpful?