blob: 7ad86712c32b63e0b18bfae39c50ceb60ede9112 [file] [log] [blame]
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -07001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5// pathological shadowed names: shadow important modules that the macros use.
6mod std {}
7mod forward_declare {}
8
9mod test_is_same_0 {
Devin Jeanpierre12dfb9a2023-01-18 14:54:41 -080010 type _Expected = ::forward_declare::internal::Symbol<()>;
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070011 fn _is_same(x: _Expected) -> ::forward_declare::symbol!("") {
12 x
13 }
14}
15
16mod test_is_same_1 {
Devin Jeanpierre12dfb9a2023-01-18 14:54:41 -080017 type _Expected = ::forward_declare::internal::Symbol<(::forward_declare::internal::C<'x'>,)>;
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070018 fn _is_same(x: _Expected) -> ::forward_declare::symbol!("x") {
19 x
20 }
21}
22
23mod test_is_same_3 {
Devin Jeanpierre12dfb9a2023-01-18 14:54:41 -080024 type _Expected = ::forward_declare::internal::Symbol<(
25 ::forward_declare::internal::C<'f'>,
26 ::forward_declare::internal::C<'o'>,
27 ::forward_declare::internal::C<'o'>,
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070028 )>;
29 fn _is_same(x: _Expected) -> ::forward_declare::symbol!("foo") {
30 x
31 }
32}
33
34#[test]
35fn test_conversions() {
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070036 use ::forward_declare::CcCast as _; // test becomes too verbose otherwise.
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070037 struct MyType;
38 type MyTypeSymbol = ::forward_declare::symbol!("X");
39 ::forward_declare::unsafe_define!(MyTypeSymbol, MyType);
40
41 let mut complete = MyType;
42 ::forward_declare::forward_declare!(MyTypeIncomplete = MyTypeSymbol);
43
44 fn ptr_location(x: impl ::std::ops::Deref) -> usize {
45 &*x as *const _ as *const u8 as usize
46 }
47
Devin Jeanpierre97a23792022-04-19 08:17:26 -070048 let loc = ptr_location(&complete);
49
50 // & -> &
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070051 {
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070052 let incomplete_ref: &MyTypeIncomplete = (&complete).cc_cast();
53 let complete_ref: &MyType = incomplete_ref.cc_cast();
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070054 assert_eq!(ptr_location(incomplete_ref), ptr_location(complete_ref));
55 }
56
Devin Jeanpierre97a23792022-04-19 08:17:26 -070057 // Pin<&> <-> Pin<&>
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070058 {
59 let incomplete_pin_ref: ::std::pin::Pin<&MyTypeIncomplete> =
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070060 ::std::pin::Pin::new(&complete).cc_cast();
61 let complete_pin_ref: ::std::pin::Pin<&MyType> = incomplete_pin_ref.cc_cast();
Devin Jeanpierre97a23792022-04-19 08:17:26 -070062 assert_eq!(ptr_location(incomplete_pin_ref), loc);
63 assert_eq!(ptr_location(complete_pin_ref), loc);
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070064 let complete_unpinned_ref: &MyType = incomplete_pin_ref.cc_cast();
Devin Jeanpierre97a23792022-04-19 08:17:26 -070065 assert_eq!(ptr_location(complete_unpinned_ref), loc);
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070066 }
67
Devin Jeanpierre97a23792022-04-19 08:17:26 -070068 // Pin<&mut> <-> Pin<&mut>
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070069 {
70 let incomplete_pin_mut: ::std::pin::Pin<&mut MyTypeIncomplete> =
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070071 ::std::pin::Pin::new(&mut complete).cc_cast();
Devin Jeanpierre97a23792022-04-19 08:17:26 -070072 assert_eq!(ptr_location(&*incomplete_pin_mut), loc);
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070073 let complete_pin_mut: ::std::pin::Pin<&mut MyType> = incomplete_pin_mut.cc_cast();
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070074 assert_eq!(ptr_location(complete_pin_mut), loc);
75 }
76
77 {
Devin Jeanpierre97a23792022-04-19 08:17:26 -070078 // &mut -> Pin<&mut>
79 let mut incomplete_pin_mut: ::std::pin::Pin<&mut MyTypeIncomplete> =
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070080 (&mut complete).cc_cast();
Devin Jeanpierre97a23792022-04-19 08:17:26 -070081 assert_eq!(ptr_location(&*incomplete_pin_mut), loc);
82 // Pin<&mut> -> &mut
83 {
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070084 let complete_unpinned_mut: &mut MyType = incomplete_pin_mut.as_mut().cc_cast();
Devin Jeanpierre97a23792022-04-19 08:17:26 -070085 assert_eq!(ptr_location(complete_unpinned_mut), loc);
86 }
87 // Pin<&mut> -> &
88 {
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -070089 let complete_unpinned_ref: &MyType = incomplete_pin_mut.as_ref().cc_cast();
Devin Jeanpierre97a23792022-04-19 08:17:26 -070090 assert_eq!(ptr_location(complete_unpinned_ref), loc);
91 }
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -070092 }
93
94 /// Typeless location&length info for a slice.
95 fn slice_location<T>(slice: &[T]) -> (usize, usize) {
96 (slice.as_ptr() as usize, slice.len())
97 }
98
Lukasz Anforowicz0e385322022-06-30 09:00:50 -070099 // Vec<&> <-> Vec<&>
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700100 {
101 let complete_vec: Vec<&MyType> = vec![&complete];
102 let loc = slice_location(&complete_vec);
103
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700104 let incomplete_vec: Vec<&MyTypeIncomplete> = complete_vec.cc_cast();
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700105 assert_eq!(slice_location(&incomplete_vec), loc);
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700106 let complete_vec: Vec<&MyType> = incomplete_vec.cc_cast();
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700107 assert_eq!(slice_location(&complete_vec), loc);
108 }
Lukasz Anforowicz0e385322022-06-30 09:00:50 -0700109
110 // &[&] <-> &[&]
111 {
112 let complete_vec: Vec<&MyType> = vec![&complete];
113 let complete_slice: &[&MyType] = complete_vec.as_slice();
114 let loc = slice_location(complete_slice);
115
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700116 let incomplete_slice: &[&MyTypeIncomplete] = complete_slice.cc_cast();
Lukasz Anforowicz0e385322022-06-30 09:00:50 -0700117 assert_eq!(slice_location(incomplete_slice), loc);
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700118 let complete_slice: &[&MyType] = incomplete_slice.cc_cast();
Lukasz Anforowicz0e385322022-06-30 09:00:50 -0700119 assert_eq!(slice_location(complete_slice), loc);
120 }
121
122 // [&; N] <-> [&; N]
123 {
124 let complete_array: [&MyType; 2] = [&complete, &complete];
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700125 let incomplete_array: [&MyTypeIncomplete; 2] = complete_array.cc_cast();
Lukasz Anforowicz0e385322022-06-30 09:00:50 -0700126 // TODO(jeanpierreda, lukasza): Avoid copying the array to a different memory location
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700127 // (maybe by tweaking `cc_cast()` to use `std::mem::transmute`
Lukasz Anforowicz0e385322022-06-30 09:00:50 -0700128 // instead of `std::mem::transmute_copy` when the input and output types
129 // are both `Sized`). Once that is done, we should be able to add
130 // asserts that say:
131 //
132 // let loc = slice_location(&complete_array);
133 // ...
134 // assert_eq!(slice_location(&incomplete_array), loc)
135 // ...
136 // assert_eq!(slice_location(&complete_array), loc)
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700137 let _complete_array: [&MyType; 2] = incomplete_array.cc_cast();
Lukasz Anforowicz0e385322022-06-30 09:00:50 -0700138 }
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700139}
140
141/// You should be able to call unsafe_define!() twice (on different types) in
142/// the same scope.
143#[test]
144fn test_hygiene() {
145 struct MyType1;
146 type MyTypeSymbol1 = ::forward_declare::symbol!("X1");
147 ::forward_declare::unsafe_define!(MyTypeSymbol1, MyType1);
148
149 struct MyType2;
150 type MyTypeSymbol2 = ::forward_declare::symbol!("X2");
151 ::forward_declare::unsafe_define!(MyTypeSymbol2, MyType2);
152}
153
154/// Suppose a library used to define its API using an incomplete type, but
155/// changed to using a complete type?
156/// This test verifies that callers continue to work as normal.
157///
158/// (The reverse direction, fundamentally, is a lot less likely to work in
159/// idiomatic code.)
160#[test]
161fn test_formerly_incomplete() {
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700162 use ::forward_declare::CcCast as _; // test becomes too verbose otherwise.
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700163 struct MyType;
164 ::forward_declare::unsafe_define!(::forward_declare::symbol!("X"), MyType);
165
166 mod callee {
167 ::forward_declare::forward_declare!(pub MyType = ::forward_declare::symbol!("X"));
168 }
169 mod caller {
170 ::forward_declare::forward_declare!(pub MyType = ::forward_declare::symbol!("X"));
171 }
172 fn takes_incomplete(_: &callee::MyType) {}
173 fn takes_complete(_: &MyType) {}
174
175 // calls which previously were converting a complete type to incomplete type are
176 // now converting a complete type to itself -- not great, but still compiles
177 // and works.
178 let x = MyType;
179 let x = &x;
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700180 takes_incomplete(x.cc_cast()); // before
181 takes_complete(x.cc_cast()); // after
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700182
Devin Jeanpierrecfd8d4a2022-07-20 13:54:29 -0700183 // Calls which previously were converting an incomplete type to an incomplete
184 // will also continue to work. In fact, this is required, since different crates
185 // will define different incomplete types.
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700186 let x: &caller::MyType = x.cc_cast();
187 takes_incomplete(x.cc_cast()); // before
188 takes_complete(x.cc_cast()); // after
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700189
190 // However, if you passed an incomplete type in without calling
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700191 // .cc_cast(), that will no longer work.
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700192 // takes_incomplete(x); // COMPILATION ERROR
193 // takes_complete(x); // COMPILATION ERROR
194
195 // Symmetrically, you can also convert complete types to incomplete if all
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700196 // callers call .cc_cast(), but this is much less reasonable a
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700197 // requirement.
198}
199
200/// In C++, you can define a type as so:
201/// template<typename T> struct Vector {T* x; size_t length;};
202/// and it can be passed by value, even for forward-declared T.
203/// How would this look in Rust?
204///
205/// The aim of this test is to establish that we can define such a Vector that
206/// supports conversion for complete/incomplete T, though being Rust, it cannot
207/// be passed by *value*, only by *reference*.
208///
209/// We can then add an additional trait bound on all methods, `where T :
210/// Complete`. This turns out to be easier, for silly typing reasons, than
211/// defining a whole new vector type for incomplete T.
212#[test]
213fn test_vector_alike() {
Devin Jeanpierre12dfb9a2023-01-18 14:54:41 -0800214 use ::forward_declare::{
215 forward_declare, internal::CcType, symbol, unsafe_define, CcCast, Complete,
216 };
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700217 struct MyComplete;
218 unsafe_define!(symbol!("T"), MyComplete);
219 forward_declare!(MyIncomplete = symbol!("T"));
220
221 /// An equivalent to Vector from the function comment, which is a compound
222 /// type that supports conversion.
223 struct Vector<T: ?Sized>(*mut T, usize);
Lukasz Anforowicz511d3f82022-06-30 08:39:45 -0700224 unsafe impl<T: ?Sized> CcType for Vector<T>
225 where
226 T: CcType,
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700227 {
Lukasz Anforowicz511d3f82022-06-30 08:39:45 -0700228 type Name = (Vector<()>, T::Name);
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700229 }
230
231 /// Methods on `Vector` that don't require complete `T`
232 impl<T: ?Sized> Vector<T> {
233 fn len(&self) -> usize {
234 self.1
235 }
236 }
237 /// Methods on Vector that require complete `T`.
238 impl<T: Complete> Vector<T> {
239 fn back(&self) -> Option<&T> {
240 if self.len() == 0 {
241 return None;
242 }
243 unimplemented!("An *actual* implementation is not important for this test");
244 }
245 }
246
247 fn expects_incomplete(_: &Vector<MyIncomplete>) {}
248 fn expects_complete(_: &Vector<MyComplete>) {}
249
250 let complete = &Vector(0 as *mut MyComplete, 0);
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700251 let incomplete: &Vector<MyIncomplete> = complete.cc_cast();
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700252
Lukasz Anforowiczbdc54be2022-06-30 10:47:21 -0700253 expects_incomplete(complete.cc_cast());
254 expects_incomplete(incomplete.cc_cast());
255 expects_complete(incomplete.cc_cast());
256 expects_complete(complete.cc_cast());
Devin Jeanpierre3dd5f4d2022-03-31 02:18:36 -0700257
258 assert!(complete.back().is_none()); // works fine
259 // incomplete.back() // compilation error due to unsatisfied trait bounds
260 // (`!Complete`)
261}