1use core::mem;
7use core::ptr;
8
9use crate::ghost_cell::*;
10
11pub trait GhostBorrow<'a, 'brand> {
15 type Result;
20
21 fn borrow(self, token: &'a GhostToken<'brand>) -> Self::Result;
40}
41
42impl<'a, 'brand, T> GhostBorrow<'a, 'brand> for &'a [GhostCell<'brand, T>] {
43 type Result = &'a [T];
44
45 fn borrow(self, _: &'a GhostToken<'brand>) -> Self::Result {
46 unsafe { mem::transmute::<Self, Self::Result>(self) }
50 }
51}
52
53impl<'a, 'brand, T, const N: usize> GhostBorrow<'a, 'brand> for &'a [GhostCell<'brand, T>; N] {
54 type Result = &'a [T; N];
55
56 fn borrow(self, _: &'a GhostToken<'brand>) -> Self::Result {
57 unsafe { mem::transmute::<Self, Self::Result>(self) }
61 }
62}
63
64impl<'a, 'brand, T: ?Sized, const N: usize> GhostBorrow<'a, 'brand> for [&'a GhostCell<'brand, T>; N] {
65 type Result = [&'a T; N];
66
67 fn borrow(self, _: &'a GhostToken<'brand>) -> Self::Result {
68 unsafe { ptr::read(&self as *const _ as *const Self::Result) }
73 }
74}
75
76macro_rules! last {
77 () => {};
78 ($head:ident $(,)?) => {
79 $head
80 };
81 ($head:ident, $($tail:ident),+ $(,)?) => {
82 last!($($tail),+)
83 };
84}
85
86macro_rules! generate_public_instance {
87 ( $($name:ident),* ; $($type_letter:ident),* ) => {
88 impl<'a, 'brand, $($type_letter: ?Sized,)*> GhostBorrow<'a, 'brand>
89 for ( $(&'a GhostCell<'brand, $type_letter>, )* )
90 {
91 type Result = ( $(&'a $type_letter, )* );
92
93 fn borrow(self, token: &'a GhostToken<'brand>) -> Self::Result {
94 let ($($name,)*) = self;
95
96 ( $( $name.borrow(token),)* )
97 }
98 }
99
100 impl<'a, 'brand, $($type_letter,)*> GhostBorrow<'a, 'brand>
101 for &'a ( $(GhostCell<'brand, $type_letter>, )* )
102 where
103 last!( $($type_letter),* ): ?Sized
104 {
105 type Result = &'a ( $($type_letter, )* );
106
107 fn borrow(self, _: &'a GhostToken<'brand>) -> Self::Result {
108 unsafe { core::mem::transmute::<Self, Self::Result>(self) }
112 }
113 }
114 };
115}
116
117generate_public_instance!(a ; T0);
118generate_public_instance!(a, b ; T0, T1);
119generate_public_instance!(a, b, c ; T0, T1, T2);
120generate_public_instance!(a, b, c, d ; T0, T1, T2, T3);
121generate_public_instance!(a, b, c, d, e ; T0, T1, T2, T3, T4);
122generate_public_instance!(a, b, c, d, e, f ; T0, T1, T2, T3, T4, T5);
123generate_public_instance!(a, b, c, d, e, f, g ; T0, T1, T2, T3, T4, T5, T6);
124generate_public_instance!(a, b, c, d, e, f, g, h ; T0, T1, T2, T3, T4, T5, T6, T7);
125generate_public_instance!(a, b, c, d, e, f, g, h, i ; T0, T1, T2, T3, T4, T5, T6, T7, T8);
126generate_public_instance!(a, b, c, d, e, f, g, h, i, j ; T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
127generate_public_instance!(a, b, c, d, e, f, g, h, i, j, k ; T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA);
128generate_public_instance!(a, b, c, d, e, f, g, h, i, j, k, l ; T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB);
129
130#[cfg(test)]
131mod tests {
132
133 use super::*;
134
135 #[test]
136 fn multiple_borrows_tuple() {
137 let value = GhostToken::new(|token| {
138 let cell1 = GhostCell::new(42);
139 let cell2 = GhostCell::new(47);
140 let cell3 = GhostCell::new(7);
141 let cell4 = GhostCell::new(9);
142
143 let (reference1, reference2, reference3, reference4): (&i32, &i32, &i32, &i32) =
144 (&cell1, &cell2, &cell3, &cell4).borrow(&token);
145
146 (*reference1, *reference2, *reference3, *reference4)
147 });
148 assert_eq!((42, 47, 7, 9), value);
149 }
150
151 #[test]
152 fn multiple_borrows_tuple_ref() {
153 let value = GhostToken::new(|token| {
154 let cell1 = GhostCell::new(42);
155 let cell2 = GhostCell::new(47);
156 let cell3 = GhostCell::new(7);
157 let cell4 = GhostCell::new(9);
158 let tuple = (cell1, cell2, cell3, cell4);
159
160 let reference: &(i32, i32, i32, i32) = tuple.borrow(&token);
161
162 (reference.0, reference.1, reference.2, reference.3)
163 });
164 assert_eq!((42, 47, 7, 9), value);
165 }
166
167 #[test]
168 fn multiple_borrows_array_ref() {
169 let value = GhostToken::new(|token| {
170 let cell1 = GhostCell::new(42);
171 let cell2 = GhostCell::new(47);
172 let cell3 = GhostCell::new(7);
173 let cell4 = GhostCell::new(9);
174 let array = [cell1, cell2, cell3, cell4];
175
176 let reference: &[i32; 4] = array.borrow(&token);
177
178 (reference[0], reference[1], reference[2], reference[3])
179 });
180 assert_eq!((42, 47, 7, 9), value);
181 }
182
183 #[test]
184 fn multiple_borrows_tuple_unsized() {
185 let value = GhostToken::new(|token| {
186 let mut data1 = 42;
187 let mut data2 = [47];
188 let mut data3 = 7;
189 let mut data4 = [9];
190
191 let cell1 = &*GhostCell::from_mut(&mut data1 as &mut dyn ToString);
192 let cell2 = &*GhostCell::from_mut(&mut data2 as &mut [i32]);
193 let cell3 = &*GhostCell::from_mut(&mut data3 as &mut dyn ToString);
194 let cell4 = &*GhostCell::from_mut(&mut data4 as &mut [i32]);
195
196 let (reference1, reference2, reference3, reference4) = (cell1, cell2, cell3, cell4).borrow(&token);
197
198 (
199 reference1.to_string(),
200 reference2[0],
201 reference3.to_string(),
202 reference4[0],
203 )
204 });
205 assert_eq!(("42".to_owned(), 47, "7".to_owned(), 9), value);
206 }
207
208 #[test]
209 fn multiple_borrows_array_unsized_slice() {
210 let value = GhostToken::new(|token| {
211 let mut data1 = [42];
212 let mut data2 = [47];
213 let mut data3 = [7];
214 let mut data4 = [9];
215
216 let cell1 = &*GhostCell::from_mut(&mut data1 as &mut [i32]);
217 let cell2 = &*GhostCell::from_mut(&mut data2 as &mut [i32]);
218 let cell3 = &*GhostCell::from_mut(&mut data3 as &mut [i32]);
219 let cell4 = &*GhostCell::from_mut(&mut data4 as &mut [i32]);
220 let array = [cell1, cell2, cell3, cell4];
221
222 let reference: [&[i32]; 4] = array.borrow(&token);
223
224 reference.map(|slice| slice[0])
225 });
226 assert_eq!([42, 47, 7, 9], value);
227 }
228
229 #[test]
230 fn multiple_borrows_array_unsized_dyn_trait() {
231 let value = GhostToken::new(|token| {
232 let mut data1 = 42;
233 let mut data2 = 47;
234 let mut data3 = 7;
235 let mut data4 = 9;
236
237 let cell1 = &*GhostCell::from_mut(&mut data1 as &mut dyn ToString);
238 let cell2 = &*GhostCell::from_mut(&mut data2 as &mut dyn ToString);
239 let cell3 = &*GhostCell::from_mut(&mut data3 as &mut dyn ToString);
240 let cell4 = &*GhostCell::from_mut(&mut data4 as &mut dyn ToString);
241 let array = [cell1, cell2, cell3, cell4];
242
243 let reference: [&dyn ToString; 4] = array.borrow(&token);
244
245 reference.map(ToString::to_string)
246 });
247 assert_eq!(
248 ["42".to_owned(), "47".to_owned(), "7".to_owned(), "9".to_owned()],
249 value
250 );
251 }
252}