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

How to reuse an opaque Rust type across bridges? #942

Closed
Minoru opened this issue Sep 25, 2021 · 3 comments
Closed

How to reuse an opaque Rust type across bridges? #942

Minoru opened this issue Sep 25, 2021 · 3 comments

Comments

@Minoru
Copy link

Minoru commented Sep 25, 2021

I've got a situation similar to #465, yet a bit different.

Suppose I have a module that produces a certain resource. The resource is represented by an opaque Rust type:

// src/handle.rs
pub struct Process {
    pub raw: u32,
}

#[cxx::bridge(namespace = zx::ffi)]
pub mod ffi {
    extern "Rust" {
        type Process;
        fn get_process() -> Box<Process>;
    }
}

fn get_process() -> Box<Process> {
    Box::new(Process { raw: 0 })
}

I also have a module that can act on that resource (this doesn't compile):

// src/main.rs
mod handle;

#[cxx::bridge(namespace = my_usage::ffi)]
mod ffi {
    extern "Rust" {
        type Process = crate::handle::Process;
        fn print_out(process: &Process);
    }
}

fn print_out(process: &handle::Process) {
    println!("process={}", process.raw);
}

fn main() {}

The idea is to use it on the C++ side like this:

// src/test.cc
#include "cxx-handles-demo/src/main.rs.h"

void test() {
    const auto process = zx::ffi::get_process();
    my_usage::ffi::print_out(*process);
}

The error I'm getting is:

error: failed to run custom build command for `cxx-handles-demo v0.1.0 (/dev/shm/cxx-handles-demo)`

Caused by:
  process didn't exit successfully: `/dev/shm/cxx-handles-demo/target/debug/build/cxx-handles-demo-891e6f86c3e2747b/build-script-build` (exit status: 1)
  --- stderr

  error[cxxbridge]: type alias in extern "Rust" block is not supported
    ┌─ src/main.rs:6:9
    │
  6 │         type Process = crate::handle::Process;
    │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type alias in extern "Rust" block is not supported

If I apply the trick from #465, I get an error that Process doesn't implement the ExternType trait (which makes sense, because that type comes from Rust, so it's not external to Rust).

The end-goal is the same as in #465: I want to define a bridged type once, and re-use it in many different bridges. I do see a few issues that mention sharing and opaque types, but none of them seem to fit this particular situation.

@dtolnay
Copy link
Owner

dtolnay commented Sep 25, 2021

It should work if you handwrite the ExternType impl to associate the Process type in Rust with the zx::ffi::Process type in C++. We might be able to provide a derive macro for ExternType to make this more convenient.

  // add to src/handle.rs

+ use cxx::{type_id, ExternType};
+
+ unsafe impl ExternType for Process {
+     type Id = type_id!("zx::ffi::Process");
+     type Kind = cxx::kind::Opaque;
+ }
  // add to src/main.rs

  mod ffi {
+     #[namespace = "zx::ffi"]
+     extern "C++" {
+         include!("cxx-handles-demo/src/handle.rs.h");
+
+         type Process = crate::handle::Process;
+     }

Minoru added a commit to dennisschagt/newsboat that referenced this issue Sep 25, 2021
Kudos to @dtolnay for providing the solution in
dtolnay/cxx#942 (and, indeed, for providing
the entire cxx crate :)
@Minoru
Copy link
Author

Minoru commented Sep 25, 2021

Yup, that works; thanks! The docs for ExternType led me to believe that it's for types exposed by C++. I'll think what could be rephrased to make the situation clearer.

@Minoru Minoru closed this as completed Sep 25, 2021
@dtolnay
Copy link
Owner

dtolnay commented Sep 26, 2021

Yeah you're right. ExternType is really the association between any type in the Rust type system with the corresponding type in the C++ type system.

dennisschagt added a commit to dennisschagt/newsboat that referenced this issue Jan 5, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to dennisschagt/newsboat that referenced this issue Jan 5, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to dennisschagt/newsboat that referenced this issue Jan 6, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to newsboat/newsboat that referenced this issue Apr 6, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to newsboat/newsboat that referenced this issue Jun 24, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to newsboat/newsboat that referenced this issue Jul 6, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to newsboat/newsboat that referenced this issue Sep 4, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to newsboat/newsboat that referenced this issue Sep 4, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
dennisschagt added a commit to newsboat/newsboat that referenced this issue Sep 4, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
Minoru pushed a commit to newsboat/newsboat that referenced this issue Oct 1, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
Minoru pushed a commit to newsboat/newsboat that referenced this issue Nov 22, 2024
Discovered that we can use `Pin<&mut ...>` to allow mutation of Rust
types defined in another cxx bridge module, based on:
- https://cxx.rs/extern-c++.html#opaque-c-types
  > Unlike extern Rust types and shared types, an extern C++ type is not
  > permitted to be passed by plain mutable reference &mut MyType across the
  > FFI bridge. For mutation support, the bridge is required to use Pin<&mut
  > MyType>. This is to safeguard against things like mem::swap-ing the
  > contents of two mutable references, given that Rust doesn't have
  > information about the size of the underlying object and couldn't invoke
  > an appropriate C++ move constructor anyway.
- dtolnay/cxx#942
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants