Re-add deleted tests from `prototype/*/non_trivially_relocatable_class/`.
The other tests are pretty uninteresting / already present here, but these three tests were sadly unique to the prototype directory.
(I'd been meaning to delete `prototype/` myself, after moving these tests, but let myself procrastinate too long, oops!)
PiperOrigin-RevId: 585881186
Change-Id: Icbc533988b21034973f6a32b341a67b16ac5b047
diff --git a/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs b/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs
index 0683a1d..8c9db0b 100644
--- a/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs
+++ b/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs
@@ -1,11 +1,12 @@
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#![feature(negative_impls)]
#[cfg(test)]
mod tests {
- use ctor::{ctor, ConstRvalueReference, RvalueReference};
- use ctor::{Assign as _, CtorNew as _};
+ use ctor::{ctor, emplace, mov, ConstRvalueReference, Ctor, Emplace, RvalueReference};
+ use ctor::{Assign as _, CtorNew as _, ReconstructUnchecked as _};
use nonunpin::{Nonmovable, Nonunpin, NonunpinStruct, ReturnsNonmovable};
use std::pin::Pin;
@@ -178,4 +179,85 @@
}
assert_eq!(x.addr, &*x as *const _ as usize);
}
+
+ /// An example showing a C++ non-trivially-relocatable class as a field in a
+ /// Rust struct. There are two ways to do this:
+ ///
+ /// 1. storing C++ class indirectly (e.g., in a Box), or,
+ /// 2. storing by-value.
+ ///
+ /// This test specicially demonstrates the second: storing a C++ class by
+ /// value, even in the worst case of it not being trivially-relocatable.
+ /// In that case, the struct containing it must *also* become
+ /// non-trivially-relocatable, and it becomes ~exactly as difficult to deal
+ /// with as the C++ class it contains.
+ #[test]
+ fn test_struct_field() {
+ #[ctor::recursively_pinned]
+ struct MyStruct {
+ field_1: u32,
+ field_2: Nonunpin,
+ }
+
+ impl MyStruct {
+ fn new() -> impl Ctor<Output = Self> {
+ ctor!(MyStruct { field_1: 4, field_2: Nonunpin::ctor_new(2) })
+ }
+ }
+
+ emplace! { let mut my_struct = MyStruct::new(); }
+ assert_eq!(my_struct.field_1, 4);
+ assert_eq!(my_struct.field_2.value(), 2);
+ // use projection (from recursively_pinned/pin_project) to mutate the struct:
+ let mut my_struct = my_struct.project_pin();
+ *my_struct.field_1 = 5;
+ my_struct.field_2.as_mut().assign(mov!(emplace!(Nonunpin::ctor_new(3))));
+ assert_eq!(*my_struct.field_1, 5);
+ assert_eq!(my_struct.field_2.value(), 3);
+ }
+
+ /// An example showing a C++ non-trivially-relocatable class as a field in a
+ /// Rust union. This mirrors the struct case, storing by value.
+ ///
+ /// It is also quite ugly, but, fortunately, these unions are not common.
+ #[test]
+ fn test_union_field() {
+ union MyUnion {
+ int: u32,
+ cxx_class: ::std::mem::ManuallyDrop<Nonunpin>,
+ }
+ unsafe impl ctor::RecursivelyPinned for MyUnion {
+ type CtorInitializedFields = Self;
+ }
+
+ // No safe helpers here. :)
+ unsafe {
+ emplace! {
+ let mut my_union = ctor!(MyUnion {
+ cxx_class: ctor::ManuallyDropCtor::new(Nonunpin::ctor_new(4))
+ });
+ }
+ assert_eq!(my_union.cxx_class.value(), 4);
+ std::mem::ManuallyDrop::drop(
+ &mut Pin::into_inner_unchecked(my_union.as_mut()).cxx_class,
+ );
+ my_union.as_mut().reconstruct_unchecked(ctor!(MyUnion { int: 2 }));
+ assert_eq!(my_union.int, 2);
+ }
+ }
+
+ /// The example from the ctor.rs docs; copy-pasted.
+ #[test]
+ fn test_swap() {
+ fn swap(mut x: Pin<&mut Nonunpin>, mut y: Pin<&mut Nonunpin>) {
+ emplace! { let mut tmp = mov!(x.as_mut()); }
+ x.assign(mov!(y.as_mut()));
+ y.assign(mov!(tmp));
+ }
+ let mut c1 = Box::emplace(Nonunpin::ctor_new(1));
+ let mut c2 = Box::emplace(Nonunpin::ctor_new(2));
+ swap(c1.as_mut(), c2.as_mut());
+ assert_eq!(c1.value(), 2);
+ assert_eq!(c2.value(), 1);
+ }
}
diff --git a/support/ctor.rs b/support/ctor.rs
index af3e780..41a6214 100644
--- a/support/ctor.rs
+++ b/support/ctor.rs
@@ -1242,6 +1242,7 @@
mod test {
use super::*;
use std::cell::RefCell;
+ use std::pin::Pin;
use std::sync::Mutex;
#[test]