Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support rust Option and C++ std::optional #87

Open
fbeutel opened this issue Apr 6, 2020 · 11 comments
Open

Support rust Option and C++ std::optional #87

fbeutel opened this issue Apr 6, 2020 · 11 comments
Labels
new binding Involves adding a new public type to cxx crate or rust/cxx.h header

Comments

@fbeutel
Copy link

fbeutel commented Apr 6, 2020

It would greatly simplify API development if automatic Option<T> conversion was supported.

Since C++17 there is std::optional<T>, which would allow a more or less direct translation of supported types.

I had a look at #67 and the ideas and work done by @myronahn for Vec seems to be similar to what would be needed for supporting Option so maybe one could build on that...

@dtolnay dtolnay added the new binding Involves adding a new public type to cxx crate or rust/cxx.h header label Apr 28, 2020
@philipcraig
Copy link
Contributor

I'm trying an implementation of this, following the code patterns for Vec and CxxVector

@philipcraig
Copy link
Contributor

philipcraig commented May 9, 2020

#44 is required for this, along with an extra flag_if_supported("/std:c++17"), which I will add in the PR for this issue. Otherwise the MSVC compiler complains:

The contents of <optional> are available only with C++17 or later.

@philipcraig
Copy link
Contributor

Most work needed for this is clear. I can follow the RustVec and CxxVector work.

There is one difference between the already-supported types like Box, Vec and String that I'm not sure how best to tackle -- the already-supported types offer a function to get a (sometimes mut) pointer to the underlying contents, such as as_mut_ptr(). Rust Option doesn't.

So, for example, we have:

Type::RustVec(_) => quote!(#var.as_mut_ptr() as *const ::cxx::private::RustVec<_>),
and similar lines for other types nearby. @dtolnay @fbeutel have you any thoughts on how this should be handled for the RustOption type that needs to be implemented?

@dtolnay
Copy link
Owner

dtolnay commented May 9, 2020

We don't use Vec::as_mut_ptr. That line is calling MaybeUninit::as_mut_ptr.

@sbrocket
Copy link
Contributor

@philipcraig Are you still planning on working on this, or could you use help? I'm finding myself in a situation where I could really use Option, for a result-like type on an interface.

@philipcraig
Copy link
Contributor

philipcraig commented Aug 21, 2020

Hi @sbrocket, I got stalled when I realised late on that there is not a fixed repr for Rust Option, so that we will have to copy bits. It should all be doable but my approach needs to be thrown away and re-done. In short, if you would like to tackle it, please do.

My work in progress is at https://github.com/philipcraig/cxx/tree/support_option_and_std_optional. It doesn't build and has the wrong assumptions about the repr of rust Option, but some of it may be useful

@adetaylor
Copy link
Collaborator

when I realised late on that there is not a fixed repr for Rust Option

rust-lang/rust#75454 if you hadn't come across it.

@Timmmm
Copy link

Timmmm commented Feb 1, 2021

I'd be happy with a solution that always copies initially.

@JanKaul
Copy link

JanKaul commented Apr 20, 2023

I would like start the discussion again how a sharable Option type could be implemented. The problem with Rust's Option seems to be that the memory layout is not stable.

How about using an custom option type with repr(C, u8) like so:

#[repr(C, u8)]
pub enum CxxOptional<T> {
    None,
    Some(T),
}

This has the advantage that it is still a rust enum but it has a defined memory layout. Moreover, it should have the same memory layout as std::optional. According to the rust representation doc this is equivalent to:

#[repr(C)]
struct CxxOptionalRepr {
    tag: CxxOptionalDiscriminant,
    payload: CxxOptionalFields,
}

// This is the discriminant enum.
#[repr(u8)]
enum CxxOptionalDiscriminant { None, Some }

// This is the variant union.
#[repr(C)]
union CxxOptionalFields<T> {
    None: Dummy,
    Some: T
}

#[repr(C)]
struct Dummy;

The corresponding C++ type looks like:

struct CxxOptional{
  enum class Tag {
    None,
    Some,
  };

  struct Some_Body {
    T _0;
  };

  Tag tag;
  union {
    Some_Body some;
  };
};

The tag field is of type unsigned char which should make it equivalent to std::optional which uses a bool. This should work because c++ interprets 0 as false and every other number as true.

What do you think about it?

@JanKaul
Copy link

JanKaul commented Apr 20, 2023

Sadly, it turns out that the fields of std::optional are arranged the other way around:

struct optional{

  union {
    T some;
  };
  bool _engaged;
};

djmitche added a commit to djmitche/taskwarrior that referenced this issue Jul 26, 2024
In the midst of just trying to wrap the existing Rust types reasonably into C++
using cxx and building a temporary executable (`tmp`).

It seems cxx is missing a lot of useful things that make a general-purpose bridge impractical:

 - no support for trait objects
 - no support for Option<T> (dtolnay/cxx#87)

so, some creativity is required in writing the bridge, and I think it can
safely be considered TW-specific. But, that means it can also omit all of the
functionality that TW doesn't use!

TODO:
 - Finish required functionality
   - put it all in one module, as multi-module support isn't good
 - Use it from TW
 - [DONE] Delete taskchampion-lib
 - Delete src/tc/*.{cpp,h}
djmitche added a commit to djmitche/taskwarrior that referenced this issue Jul 29, 2024
In the midst of just trying to wrap the existing Rust types reasonably into C++
using cxx and building a temporary executable (`tmp`).

It seems cxx is missing a lot of useful things that make a general-purpose bridge impractical:

 - no support for trait objects
 - no support for Option<T> (dtolnay/cxx#87)

so, some creativity is required in writing the bridge, and I think it can
safely be considered TW-specific. But, that means it can also omit all of the
functionality that TW doesn't use!

TODO:
 - WIP
   - remove ffi.h
   - stashed bit is getting started with replacing src/tc, but maybe
     throw that out
 - Use it from TW
djmitche added a commit to djmitche/taskwarrior that referenced this issue Jul 31, 2024
In the midst of just trying to wrap the existing Rust types reasonably into C++
using cxx and building a temporary executable (`tmp`).

It seems cxx is missing a lot of useful things that make a general-purpose bridge impractical:

 - no support for trait objects
 - no support for Option<T> (dtolnay/cxx#87)

so, some creativity is required in writing the bridge, and I think it can
safely be considered TW-specific. But, that means it can also omit all of the
functionality that TW doesn't use!

TODO:
 - WIP
   - remove ffi.h
   - stashed bit is getting started with replacing src/tc, but maybe
     throw that out
 - Use it from TW
djmitche added a commit to djmitche/taskwarrior that referenced this issue Aug 4, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

so, some creativity is required in writing the bridge, for example
returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.

TODO:
 - See TODO's in patch
 - remove old/unnecessary files
 - Make sure error messages are still shown properly e.g., in sync
 - Docs updates
djmitche added a commit to djmitche/taskwarrior that referenced this issue Aug 5, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.

TODO:
 - reference released `taskchampion 0.7.0`
djmitche added a commit to djmitche/taskwarrior that referenced this issue Aug 7, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.

TODO:
 - reference released `taskchampion 0.7.0`
djmitche added a commit to djmitche/taskwarrior that referenced this issue Aug 7, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
djmitche added a commit to djmitche/taskwarrior that referenced this issue Aug 7, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
djmitche added a commit to djmitche/taskwarrior that referenced this issue Aug 7, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
jcgruenhage pushed a commit to jcgruenhage/taskwarrior that referenced this issue Aug 9, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
jcgruenhage pushed a commit to jcgruenhage/taskwarrior that referenced this issue Aug 9, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
jcgruenhage pushed a commit to jcgruenhage/taskwarrior that referenced this issue Aug 9, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
djmitche added a commit to GothenburgBitFactory/taskwarrior that referenced this issue Aug 11, 2024
TC 0.7.0 introduces a new `TaskData` type that maps to Taskwarrior's
`Task` type more cleanly. It also introduces the idea of gathering lists
of operations and "committing" them to a replica.

A consequence of this change is that TaskChampion no longer
automatically maintains dependency information, so Taskwarrior must do
so, with its `TDB2::dependency_sync` method. This method does a very
similar thing to what TaskChampion had been doing, so this is a shift of
responsibility but not a major performance difference.

Cxx is .. not great. It is missing a lot of useful things that make a
general-purpose bridge impractical:

 - no support for trait objects
 - no support for `Option<T>` (dtolnay/cxx#87)
 - no support for `Vec<Box<..>>`

As a result, some creativity is required in writing the bridge, for
example returning a `Vec<OptionTaskData>` from `all_task_data` to allow
individual `TaskData` values to be "taken" from the vector.

That said, Cxx is the current state-of-the-art, and does a good job of
ensuring memory safety, at the cost of some slightly awkward APIs.

Subsequent work can remove the "TDB2" layer and allow commands and other
parts of Taskwarrior to interface directly with the `Replica`.
@caesay
Copy link

caesay commented Oct 16, 2024

There seems to be some good suggestions here, but doesn't seem to be any movement in over a year. In the absence of a proper solution / support for Option<T> (or a new type like CxxOptional), what is the best current workaround when needing to pass what could be a null ptr / optional parameter from C++ to Rust?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new binding Involves adding a new public type to cxx crate or rust/cxx.h header
Projects
None yet
Development

No branches or pull requests

8 participants