blob: ca3e0cdc31054a2dac39f6e68bc8d14250ff4c0d [file] [log] [blame]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07001// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9// This example serves to demonstrate the experimental C++
10// reference wrappers. They exist because C++ references are not
11// the same as Rust references: C++ references may alias, whereas
12// Rust references may not.
13//
14// Standard autocxx behavior therefore introduces unsoundness when
15// C++ references are encountered and treated like Rust references.
16// (cxx has this soundness problem for Trivial types; autocxx
17// makes it worse in that the same problem applies even for
18// opaque types, because we make them sized such that we can allocate
19// them on the stack).
20//
21// Reference wrappers solve that problem because internally, they're
22// just pointers. On the other hand, they're awkward to use,
23// especially in the absence of the Rust "arbitrary self types"
24// feature.
25
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070026// Necessary to be able to call methods on reference wrappers.
27// For that reason, this example only builds on nightly Rust.
28#![feature(arbitrary_self_types)]
29
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070030use autocxx::prelude::*;
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070031use std::pin::Pin;
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070032
33include_cpp! {
34 #include "input.h"
35 // This next line enables C++ reference wrappers
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070036 // This is what requires the 'arbitrary_self_types' feature.
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070037 safety!(unsafe_references_wrapped)
38 generate!("Goat")
39 generate!("Field")
40}
41
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070042impl ffi::Goat {
43 // Methods can be called on a CppRef<T> or &CppRef<T>
44 fn bleat(self: CppRef<Self>) {
45 println!("Bleat");
46 }
47}
48
49trait FarmProduce {
50 // Traits can be defined on a CppRef<T> so long as Self: Sized
51 fn sell(self: &CppRef<Self>)
52 where
53 Self: Sized;
54}
55
56impl FarmProduce for ffi::Goat {
57 fn sell(self: &CppRef<Self>) {
58 println!("Selling goat");
59 }
60}
61
62trait FarmArea {
63 fn maintain(self: CppRef<Self>);
64}
65
66impl FarmArea for ffi::Field {
67 fn maintain(self: CppRef<Self>) {
68 println!("Maintaining");
69 }
70}
71
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070072fn main() {
73 // Create a cxx::UniquePtr as normal for a Field object.
74 let field = ffi::Field::new().within_unique_ptr();
75 // We assume at this point that C++ has had no opportunity
76 // to retain any reference to the Field. That's not strictly
77 // true, due to RVO, but under all reasonable circumstances
78 // Rust currently has exclusive ownership of the Field we've
79 // been given.
80 // Therefore, at this point in the program, it's still
81 // OK to take Rust references to this Field.
82 let _field_rust_ref = field.as_ref();
83 // However, as soon as we want to pass a reference to the field
84 // back to C++, we have to ensure we have no Rust references
85 // in existence. So: we imprison the object in a "CppPin":
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070086 let field = CppUniquePtrPin::new(field);
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070087 // We can no longer take Rust references to the field...
88 // let _field_rust_ref = field.as_ref();
89 // However, we can take C++ references. And use such references
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070090 // to call methods in C++. Quite often those methods will
91 // return other references, like this.
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070092 let another_goat = field.as_cpp_ref().get_goat();
93 // The 'get_goat' method in C++ returns a reference, so this is
94 // another CppRef, not a Rust reference.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070095
96 // We can still use these C++ references to call Rust methods,
97 // so long as those methods have a "self" type of a
98 // C++ reference not a Rust reference.
99 another_goat.clone().bleat();
100 another_goat.sell();
101
102 // But most commonly, C++ references are simply used as the 'this'
103 // type when calling other C++ methods, like this.
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700104 assert_eq!(
105 another_goat
106 .describe() // returns a UniquePtr<CxxString>, there
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700107 // are no Rust or C++ references involved at this point.
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700108 .as_ref()
109 .unwrap()
110 .to_string_lossy(),
111 "This goat has 0 horns."
112 );
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700113
114 // We can even use trait objects, though it's a bit of a fiddle.
115 let farm_area: Pin<Box<dyn FarmArea>> = ffi::Field::new().within_box();
116 let farm_area = CppPin::from_pinned_box(farm_area);
117 farm_area.as_cpp_ref().maintain();
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700118}