Skip to content

Commit 78043e4

Browse files
committed
tests: internal: add tests for new tuple struct support
Tests include: - `tests/tuple_struct.rs` - `tests/ui/compile-fail/tuple_{duplicate,invalid,missing}_field.rs` - `tests/ui/compile-fail/tuple_shorthand.rs` - `tests/ui/expand/pin_{data,init}` Signed-off-by: Mohamad Alsadhan <mo@sdhn.cc>
1 parent d5045f4 commit 78043e4

13 files changed

+478
-0
lines changed

tests/tuple_struct.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
2+
3+
use core::ptr;
4+
5+
use pin_init::*;
6+
7+
#[pin_data]
8+
struct TupleStruct(#[pin] i32, i32);
9+
10+
fn init_i32(value: i32) -> impl PinInit<i32> {
11+
// SAFETY: The closure always initializes `slot` with a valid `i32` value.
12+
unsafe {
13+
pin_init_from_closure(move |slot| {
14+
// SAFETY: `slot` is provided by the initialization framework and valid for write.
15+
ptr::write(slot, value);
16+
Ok(())
17+
})
18+
}
19+
}
20+
21+
fn init_i32_unpinned(value: i32) -> impl Init<i32> {
22+
// SAFETY: The closure always initializes `slot` with a valid `i32` value.
23+
unsafe {
24+
init_from_closure(move |slot| {
25+
// SAFETY: `slot` is provided by the initialization framework and valid for write.
26+
ptr::write(slot, value);
27+
Ok(())
28+
})
29+
}
30+
}
31+
32+
#[test]
33+
#[allow(clippy::just_underscores_and_digits)]
34+
fn tuple_struct_values() {
35+
stack_pin_init!(let foo = pin_init!(TupleStruct { 0: 42, 1: 24 }));
36+
assert_eq!(foo.as_ref().get_ref().0, 42);
37+
assert_eq!(foo.as_ref().get_ref().1, 24);
38+
}
39+
40+
#[test]
41+
#[allow(clippy::just_underscores_and_digits)]
42+
fn tuple_struct_init_arrow_and_projection() {
43+
stack_pin_init!(let foo = pin_init!(TupleStruct { 0 <- init_i32(7), 1: 13 }));
44+
let mut foo = foo;
45+
let projected = foo.as_mut().project();
46+
assert_eq!(*projected._0.as_ref().get_ref(), 7);
47+
assert_eq!(*projected._1, 13);
48+
}
49+
50+
#[test]
51+
#[allow(clippy::just_underscores_and_digits)]
52+
fn tuple_struct_constructor_form() {
53+
stack_pin_init!(let foo = pin_init!(TupleStruct(<- init_i32(11), 29)));
54+
assert_eq!(foo.as_ref().get_ref().0, 11);
55+
assert_eq!(foo.as_ref().get_ref().1, 29);
56+
}
57+
58+
#[pin_data]
59+
struct Triple(i32, i32, i32);
60+
61+
#[test]
62+
fn tuple_struct_constructor_form_mixed_middle_init() {
63+
stack_pin_init!(let triple = pin_init!(Triple(1, <- init_i32_unpinned(2), 3)));
64+
assert_eq!(triple.as_ref().get_ref().0, 1);
65+
assert_eq!(triple.as_ref().get_ref().1, 2);
66+
assert_eq!(triple.as_ref().get_ref().2, 3);
67+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use pin_init::*;
2+
3+
#[pin_data]
4+
struct Tuple(#[pin] i32, i32);
5+
6+
fn main() {
7+
let _ = pin_init!(Tuple { 0: 1, 0: 2, 1: 3 });
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error[E0062]: field `0` specified more than once
2+
--> tests/ui/compile-fail/init/tuple_duplicate_field.rs:7:37
3+
|
4+
7 | let _ = pin_init!(Tuple { 0: 1, 0: 2, 1: 3 });
5+
| ------------------------^------------
6+
| | |
7+
| | used more than once
8+
| first use of `0`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use pin_init::*;
2+
3+
#[pin_data]
4+
struct Tuple(#[pin] i32, i32);
5+
6+
fn main() {
7+
let _ = pin_init!(Tuple { 0: 1, 1: 2, 2: 3 });
8+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0609]: no field `2` on type `Tuple`
2+
--> tests/ui/compile-fail/init/tuple_invalid_field.rs:7:43
3+
|
4+
7 | let _ = pin_init!(Tuple { 0: 1, 1: 2, 2: 3 });
5+
| ^ unknown field
6+
|
7+
= note: available fields are: `0`, `1`
8+
9+
error[E0599]: no method named `__project_2` found for struct `__ThePinData` in the current scope
10+
--> tests/ui/compile-fail/init/tuple_invalid_field.rs:7:13
11+
|
12+
3 | #[pin_data]
13+
| ----------- method `__project_2` not found for this struct
14+
...
15+
7 | let _ = pin_init!(Tuple { 0: 1, 1: 2, 2: 3 });
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
|
18+
= note: this error originates in the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info)
19+
20+
error[E0560]: struct `Tuple` has no field named `2`
21+
--> tests/ui/compile-fail/init/tuple_invalid_field.rs:7:43
22+
|
23+
4 | struct Tuple(#[pin] i32, i32);
24+
| ----- `Tuple` defined here
25+
...
26+
7 | let _ = pin_init!(Tuple { 0: 1, 1: 2, 2: 3 });
27+
| ^ field does not exist
28+
|
29+
help: `Tuple` is a tuple struct, use the appropriate syntax
30+
|
31+
7 - let _ = pin_init!(Tuple { 0: 1, 1: 2, 2: 3 });
32+
7 + let _ = Tuple(/* i32 */, /* i32 */);
33+
|
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use pin_init::*;
2+
3+
#[pin_data]
4+
struct Tuple(#[pin] i32, i32);
5+
6+
fn main() {
7+
let _ = pin_init!(Tuple { 0: 1 });
8+
let _ = init!(Tuple { 0: 1 });
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0063]: missing field `1` in initializer of `Tuple`
2+
--> tests/ui/compile-fail/init/tuple_missing_field.rs:7:23
3+
|
4+
7 | let _ = pin_init!(Tuple { 0: 1 });
5+
| ^^^^^ missing `1`
6+
7+
error[E0063]: missing field `1` in initializer of `Tuple`
8+
--> tests/ui/compile-fail/init/tuple_missing_field.rs:8:19
9+
|
10+
8 | let _ = init!(Tuple { 0: 1 });
11+
| ^^^^^ missing `1`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use pin_init::*;
2+
3+
#[pin_data]
4+
struct Tuple(#[pin] i32, i32);
5+
6+
fn main() {
7+
let _ = pin_init!(Tuple { 0, 1: 24 });
8+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: expected `<-` or `:`
2+
--> tests/ui/compile-fail/init/tuple_shorthand.rs:7:32
3+
|
4+
7 | let _ = pin_init!(Tuple { 0, 1: 24 });
5+
| ^
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use pin_init::*;
2+
struct Foo([u8; 1024 * 1024], i32);
3+
/// Pin-projections of [`Foo`]
4+
#[allow(dead_code)]
5+
#[doc(hidden)]
6+
struct FooProjection<'__pin> {
7+
_0: &'__pin mut [u8; 1024 * 1024],
8+
_1: ::core::pin::Pin<&'__pin mut i32>,
9+
___pin_phantom_data: ::core::marker::PhantomData<&'__pin mut ()>,
10+
}
11+
impl Foo {
12+
/// Pin-projects all fields of `Self`.
13+
///
14+
/// These fields are structurally pinned:
15+
/// - index `1`
16+
///
17+
/// These fields are **not** structurally pinned:
18+
/// - index `0`
19+
#[inline]
20+
fn project<'__pin>(
21+
self: ::core::pin::Pin<&'__pin mut Self>,
22+
) -> FooProjection<'__pin> {
23+
let this = unsafe { ::core::pin::Pin::get_unchecked_mut(self) };
24+
FooProjection {
25+
_0: &mut this.0,
26+
_1: unsafe { ::core::pin::Pin::new_unchecked(&mut this.1) },
27+
___pin_phantom_data: ::core::marker::PhantomData,
28+
}
29+
}
30+
}
31+
const _: () = {
32+
#[doc(hidden)]
33+
struct __ThePinData {
34+
__phantom: ::core::marker::PhantomData<fn(Foo) -> Foo>,
35+
}
36+
impl ::core::clone::Clone for __ThePinData {
37+
fn clone(&self) -> Self {
38+
*self
39+
}
40+
}
41+
impl ::core::marker::Copy for __ThePinData {}
42+
#[allow(dead_code)]
43+
#[expect(clippy::missing_safety_doc)]
44+
impl __ThePinData {
45+
/// # Safety
46+
///
47+
/// - `slot` is a valid pointer to uninitialized memory.
48+
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
49+
/// to deallocate.
50+
unsafe fn _0<E>(
51+
self,
52+
slot: *mut [u8; 1024 * 1024],
53+
init: impl ::pin_init::Init<[u8; 1024 * 1024], E>,
54+
) -> ::core::result::Result<(), E> {
55+
unsafe { ::pin_init::Init::__init(init, slot) }
56+
}
57+
/// # Safety
58+
///
59+
/// `slot` points at the field index `0` inside of `Foo`, which is pinned.
60+
unsafe fn __project_0<'__slot>(
61+
self,
62+
slot: &'__slot mut [u8; 1024 * 1024],
63+
) -> &'__slot mut [u8; 1024 * 1024] {
64+
slot
65+
}
66+
/// # Safety
67+
///
68+
/// - `slot` is a valid pointer to uninitialized memory.
69+
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted
70+
/// to deallocate.
71+
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
72+
unsafe fn _1<E>(
73+
self,
74+
slot: *mut i32,
75+
init: impl ::pin_init::PinInit<i32, E>,
76+
) -> ::core::result::Result<(), E> {
77+
unsafe { ::pin_init::PinInit::__pinned_init(init, slot) }
78+
}
79+
/// # Safety
80+
///
81+
/// `slot` points at the field index `1` inside of `Foo`, which is pinned.
82+
unsafe fn __project_1<'__slot>(
83+
self,
84+
slot: &'__slot mut i32,
85+
) -> ::core::pin::Pin<&'__slot mut i32> {
86+
unsafe { ::core::pin::Pin::new_unchecked(slot) }
87+
}
88+
}
89+
unsafe impl ::pin_init::__internal::HasPinData for Foo {
90+
type PinData = __ThePinData;
91+
unsafe fn __pin_data() -> Self::PinData {
92+
__ThePinData {
93+
__phantom: ::core::marker::PhantomData,
94+
}
95+
}
96+
}
97+
unsafe impl ::pin_init::__internal::PinData for __ThePinData {
98+
type Datee = Foo;
99+
}
100+
#[allow(dead_code)]
101+
struct __Unpin<'__pin> {
102+
__phantom_pin: ::core::marker::PhantomData<fn(&'__pin ()) -> &'__pin ()>,
103+
__phantom: ::core::marker::PhantomData<fn(Foo) -> Foo>,
104+
_1: i32,
105+
}
106+
#[doc(hidden)]
107+
impl<'__pin> ::core::marker::Unpin for Foo
108+
where
109+
__Unpin<'__pin>: ::core::marker::Unpin,
110+
{}
111+
trait MustNotImplDrop {}
112+
#[expect(drop_bounds)]
113+
impl<T: ::core::ops::Drop + ?::core::marker::Sized> MustNotImplDrop for T {}
114+
impl MustNotImplDrop for Foo {}
115+
#[expect(non_camel_case_types)]
116+
trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
117+
impl<
118+
T: ::pin_init::PinnedDrop + ?::core::marker::Sized,
119+
> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
120+
impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for Foo {}
121+
};

0 commit comments

Comments
 (0)