-
Notifications
You must be signed in to change notification settings - Fork 386
Description
Hello,
I've long been interested in seeing of CXX could help in making rust bindings to TaskWarrior, though it looks like @djmitche is incorporating rust into the project in a different route (which is exciting to see) -- so this is mostly an experiment for my learning at this point.
I don't know C or C++, so I'm starting from a fairly disadvantaged perspective.
Using bindgen alone, I was able to get taskwarrior's Context::dispatch
to work from Rust, so I wanted to convert my work (just a few lines of code) to CXX to compare.
TaskWarrior source
taskwarrior-sys (bindgen)
- https://github.com/n8henrie/taskwarrior-rs/tree/master/taskwarrior-sys
- See
wrapper.{cpp,h}
andsrc/lib.rs
Hopefully my terminology is correct, but it seems that Taskwarrior uses this approach:
- declares a uninitialized global
Context
(a singleton?) Context::setContext (&globalContext);
, which setsContext::context
to the global context- Calls
Context::getContext
for all subsequent calls - Initializes the context
- Calls
Context::run
, which delegates toContext::dispatch
To translate this to cxx, it looks like there may be a couple of challenges, for example regarding constructors:
- It seems like the rust signature would be
Context::new() -> Self
, but cxx seems to require some kind ofself: &Context
argument to define something as a method- Distinguish static member function on shared structs #447
- This also made it difficult for me to determine the signatures for the
static
methods such assetContext
andgetContext
- Some of the issues with constructors are reviewed in Provide builtin handling of exposing a C++ constructor #280
- In that issue, use of a shim to return a
UniquePtr
seems to be recommended
Here is my attempt, with several lines commented out from previous attempts:
taskwarrior-sys (cxx)
- https://github.com/n8henrie/taskwarrior-rs/blob/cxx/taskwarrior-sys/src/lib.rs
- https://github.com/n8henrie/taskwarrior-rs/blob/cxx/taskwarrior-sys/shims.h
The loop I would run into was, for example:
// static Context& Context::getContext ()
fn getContext() -> &Context;
Result: error: no member named 'getContext' in the global namespace
Doesn't work because this tries to define getContext
as a free function and doesn't find the Context::getContext
method. To fix that I need a self:
parameter as noted in the issue above.
fn getContext(self: &Context) -> &Context;
result:
error: cannot initialize a variable of type 'const ::Context &(Context::*)() const' with an rvalue of type 'Context &(*)()': different return type ('const ::Context &' (aka 'const Context &') vs 'Context &')
Makes sense, I think this means that returning &Context
returns a const value instead of a mutable one
- Can't return
&mut Context
, must bePin<&mut Context>
- Can't return a
Pin<&mut ...>
without aPin<&mut ...>
input
fn getContext(self: Pin<&mut Context>) -> Pin<&mut Context>;
result:
error: cannot initialize a variable of type '::Context &(Context::*)()' with an rvalue of type 'Context &(*)()'
Unfortunately I don't really understand this, so then I tried creating a shim and creating / returning UniquePtr<Context>
.
Am I on the right track just trying to create a shim that wraps everything in std::unique_ptr
like so?
inline void Context_setContext(std::unique_ptr<Context> context) {
Context::setContext(context);
}
Sorry that this is more of a "I don't know c++" problem than a rust problem; if there's a more appropriate place to ask, please let me know!
Thank you for your time and for providing this library!