I need to implement a CSV reader that will be called from C++, essentially one call to open a file and then multiple read calls each consuming a number of lines (how many lines depends on the data, one column is time and I need chunks of equal length "time-wise"). Column names from the header needs to be available at the read calls.
I'm pretty new at Rust but my thoughts here go something like "let the open call create a reader and get an iterator for the content, store that in some "good place"(TM) and let the read calls get the iterator back and consume as much of its output that they see fit".
Control here lies in the C++ application (so far... so I need to deal with both that there are separate calls for open and read and that the API is fixed - so I cannot pass a state variable back to C++ (this is a first step replacing a C++ CSV reader, next step is providing a reader for more interesting format(s).
From my horizon this feels like something that needs a global protected by a Mutex, but I have read enough to realize that this is seen as some kind of last restort, clearly discouraged both by the language and lots of people online. So I'm looking for either confirmation; "Yes, with that need you have a thorny and painful path ahead but good luck" or alternatives: "Well, from this (much higher) horizon you could instead do like this..."
I realize that this may be quite a challenge as an early Rust project but as Mario Andretti once said - "If everything seems under control you're not going fast enough"
Can you share the API?
Can you share the API in question? It may well be the case that (knowing C and C++) there's a way for you to implement the API in a way that carries state through (e.g. because there's a return value from open
that gets passed across indirectly to read
in a way that cxx.rs will let you bind to).
Without knowing what the API surface you're dealing with is, it's really hard to give advice.
In C++ the main functions are:
bool openLogFile(const std::string &fileName)
bool prepareNextSignals(size_t &delta_t, std::vector< std::shared_ptr< Signal >> &signalsToWrite)
They are really methods on a reader class, but I expect to write a dummy class and just pass those calls to a Rust library. I am not familiar with CXX more than that I have heard the name, but I don't expect to need that kind of tools for this small project (I may be wrong here though).
Signal
is a tagged struct/union.
Then they have an (implicit) this
argument, don't they? I mean the very point of a class is to store state…
Then you don't need a global; create an opaque Rust object, and carry that about in the C++ reader class. cxx.rs will make it easier to do this, but you can do it via pure FFI calls if you wish.
I've done pure FFI when interfacing with C, using Box::into_raw
to turn a Rust boxed object into a pointer, and Box::from_raw
to turn the pointer back into a box to destroy, then I used interior mutability, and unsafe { *ptr }
to get a shared reference to my object when the pointer was passed back in by C code.
I've also used cxx.rs, and that made it much, much easier.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.