Skip to content

Commit bf2c451

Browse files
committed
Add docs for shared type aliases
1 parent 3ab1a3a commit bf2c451

File tree

1 file changed

+94
-1
lines changed

1 file changed

+94
-1
lines changed

src/extern_type.rs

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
/// A type for which the layout is determined by an external definition.
22
///
33
/// `ExternType` makes it possible for CXX to safely share a consistent Rust type across multiple
4-
/// #\[cxx::bridge\] invocations. This serves multiple related purposes.
4+
/// #\[cxx::bridge\] invocations, both for shared types defined in another bridge and external C++
5+
/// definitions. This serves multiple related purposes.
6+
///
7+
/// TODO: These docs aren't discoverable. Add a link to here from the main crate docs.
58
///
69
/// <br>
710
///
@@ -48,6 +51,96 @@
4851
///
4952
/// <br><br>
5053
///
54+
/// ## Reusing Rust/C++ shared types across multiple bridges
55+
///
56+
/// `ExternType` enables reusing a shared Rust/C++ type declared in another bridge module, allowing
57+
/// for the creation of libraries to wrap types used in multiple different bridges.
58+
///
59+
/// Imagine we have an existing move-only C++ type, file::UniqueFd, that wraps sole ownership of a
60+
/// file descriptor, analogous to Rust's std::fd::File. The example below defines a shared type
61+
/// `File` that allows safely transferring ownership of the file across the interface without Box or
62+
/// UniquePtr and without resource leaks. This type can then be reused in other bridges.
63+
///
64+
/// ```no_run
65+
/// // file/src/lib.rs
66+
/// # #[cfg(unix)]
67+
/// # mod file {
68+
/// # use std::os::unix::io::{IntoRawFd, FromRawFd};
69+
/// #[cxx::bridge(namespace = file::ffi)]
70+
/// pub mod ffi {
71+
/// /// A file backed by a file descriptor, which it is the sole owner of.
72+
/// struct File {
73+
/// fd: i32,
74+
/// }
75+
/// }
76+
///
77+
/// impl From<ffi::File> for std::fs::File {
78+
/// fn from(value: ffi::File) -> Self {
79+
/// // Safe because ffi::File owns its file descriptor.
80+
/// unsafe { Self::from_raw_fd(value.fd) }
81+
/// }
82+
/// }
83+
///
84+
/// impl From<std::fs::File> for ffi::File {
85+
/// fn from(value: std::fs::File) -> Self {
86+
/// Self { fd: value.into_raw_fd() }
87+
/// }
88+
/// }
89+
///
90+
/// impl Drop for ffi::File {
91+
/// fn drop(&mut self) {
92+
/// // Safe because ffi::File owns its file descriptor.
93+
/// unsafe { std::fs::File::from_raw_fd(self.fd); }
94+
/// }
95+
/// }
96+
/// # }
97+
///
98+
/// // file/src/lib.h
99+
/// # /*
100+
/// namespace file {
101+
///
102+
/// ffi::File TransferToFFI(File file) {
103+
/// // Imagine file::UniqueFd::release() is analogous to from_raw_fd
104+
/// return ffi::File{ .fd = file.release() };
105+
/// }
106+
///
107+
/// }
108+
/// # */
109+
///
110+
/// // TODO(https://github.com/dtolnay/cxx/pull/298): Currently this bridge must use the same
111+
/// // namespace as any bridge it creates aliases from.
112+
///
113+
/// // usage.rs
114+
/// # #[cfg(unix)]
115+
/// # mod usage {
116+
/// #[cxx::bridge(namespace = file::ffi)]
117+
/// pub mod ffi {
118+
/// type File = crate::file::ffi::File;
119+
///
120+
/// extern "C" {
121+
/// type Demo;
122+
///
123+
/// fn create_demo(file: File) -> UniquePtr<Demo>;
124+
/// }
125+
/// }
126+
/// # }
127+
///
128+
/// // usage.cc
129+
/// # /*
130+
/// file::ffi::File ConvertFile(file::UniqueFd file) {
131+
/// }
132+
///
133+
/// void CreateDemo(file::UniqueFd file) {
134+
/// auto demo = ffi::create_demo(file::TransferToFFI(std::move(file)));
135+
/// // use demo
136+
/// }
137+
/// # */
138+
///
139+
/// # fn main() {}
140+
/// ```
141+
///
142+
/// <br><br>
143+
///
51144
/// ## Integrating with bindgen-generated types
52145
///
53146
/// Handwritten `ExternType` impls make it possible to plug in a data structure emitted by bindgen

0 commit comments

Comments
 (0)