soa_derive_internal/
ptr.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3
4use crate::input::Input;
5use crate::names;
6
7pub fn derive(input: &Input) -> TokenStream {
8    let name = &input.name;
9    let visibility = &input.visibility;
10    let attrs = &input.attrs.ptr;
11    let mut_attrs = &input.attrs.ptr_mut;
12    let vec_name = names::vec_name(&input.name);
13    let ptr_name = names::ptr_name(&input.name);
14    let ptr_mut_name = names::ptr_mut_name(&input.name);
15    let ref_name = names::ref_name(&input.name);
16    let ref_mut_name = names::ref_mut_name(&input.name);
17
18    let doc_url = format!("[`{0}`](struct.{0}.html)", name);
19    let vec_doc_url = format!("[`{0}`](struct.{0}.html)", vec_name);
20    let ptr_doc_url = format!("[`{0}`](struct.{0}.html)", ptr_name);
21    let ptr_mut_doc_url = format!("[`{0}`](struct.{0}.html)", ptr_mut_name);
22    let ref_doc_url = format!("[`{0}`](struct.{0}.html)", ref_name);
23    let ref_mut_doc_url = format!("[`{0}`](struct.{0}.html)", ref_mut_name);
24
25    let fields_names = &input.fields.iter()
26        .map(|field| field.ident.clone().unwrap())
27        .collect::<Vec<_>>();
28
29    let ptr_fields_types = input.map_fields_nested_or(
30        |_, field_type| {
31            let field_ptr_type = names::ptr_name(field_type);
32            quote! { #field_ptr_type }
33        },
34        |_, field_type| quote! { *const #field_type },
35    ).collect::<Vec<_>>();
36
37    let ptr_mut_fields_types = input.map_fields_nested_or(
38        |_, field_type| {
39            let field_ptr_type = names::ptr_mut_name(field_type);
40            quote! { #field_ptr_type }
41        },
42        |_, field_type| quote! { *mut #field_type },
43    ).collect::<Vec<_>>();
44
45    let as_ptr = input.map_fields_nested_or(
46        |ident, _| quote! { self.#ident.as_ptr() },
47        |ident, _| quote! { self.#ident as *const _ },
48    ).collect::<Vec<_>>();
49
50    let as_mut_ptr = input.map_fields_nested_or(
51        |ident, _| quote! { self.#ident.as_mut_ptr() },
52        |ident, _| quote! { self.#ident as *mut _ },
53    ).collect::<Vec<_>>();
54
55    quote! {
56        /// An analog of a pointer to
57        #[doc = #doc_url]
58        /// with struct of array layout.
59        #(#[#attrs])*
60        #[derive(Copy, Clone)]
61        #visibility struct #ptr_name {
62            #(
63                /// pointer to the `
64                #[doc = stringify!(#fields_names)]
65                ///` field of a single
66                #[doc = #doc_url]
67                /// inside a
68                #[doc = #vec_doc_url]
69                pub #fields_names: #ptr_fields_types,
70            )*
71        }
72
73        /// An analog of a mutable pointer to
74        #[doc = #doc_url]
75        /// with struct of array layout.
76        #(#[#mut_attrs])*
77        #[derive(Copy, Clone)]
78        #visibility struct #ptr_mut_name {
79            #(
80                /// pointer to the `
81                #[doc = stringify!(#fields_names)]
82                ///` field of a single
83                #[doc = #doc_url]
84                /// inside a
85                #[doc = #vec_doc_url]
86                pub #fields_names: #ptr_mut_fields_types,
87            )*
88        }
89
90        #[allow(dead_code)]
91        impl #ptr_name {
92            /// Convert a
93            #[doc = #ptr_doc_url]
94            /// to a
95            #[doc = #ptr_mut_doc_url]
96            /// ; *i.e.* do a `*const T as *mut T` transformation.
97            #visibility fn as_mut_ptr(&self) -> #ptr_mut_name {
98                #ptr_mut_name {
99                    #( #fields_names: #as_mut_ptr, )*
100                }
101            }
102
103            /// Similar to [`*const T::is_null()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.is_null).
104            pub fn is_null(self) -> bool {
105                false #( || self.#fields_names.is_null())*
106            }
107
108            /// Similar to [`*const T::as_ref()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref),
109            /// with the same safety caveats.
110            pub unsafe fn as_ref<'a>(self) -> Option<#ref_name<'a>> {
111                if self.is_null() {
112                    None
113                } else {
114                    Some(#ref_name {
115                        #(#fields_names: self.#fields_names.as_ref().expect("should not be null"), )*
116                    })
117                }
118            }
119
120            /// Similar to [`*const T::offset()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.offset),
121            /// with the same safety caveats.
122            pub unsafe fn offset(self, count: isize) -> #ptr_name {
123                #ptr_name {
124                    #(#fields_names: self.#fields_names.offset(count), )*
125                }
126            }
127
128            /// Similar to [`*const T::offset()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.offset).
129            pub fn wrapping_offset(self, count: isize) -> #ptr_name {
130                #ptr_name {
131                    #(#fields_names: self.#fields_names.wrapping_offset(count), )*
132                }
133            }
134
135            /// Similar to [`*const T::add()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.add),
136            /// with the same safety caveats.
137            pub unsafe fn add(self, count: usize) -> #ptr_name {
138                #ptr_name {
139                    #(#fields_names: self.#fields_names.add(count), )*
140                }
141            }
142
143            /// Similar to [`*const T::sub()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.sub),
144            /// with the same safety caveats.
145            pub unsafe fn sub(self, count: usize) -> #ptr_name {
146                #ptr_name {
147                    #(#fields_names: self.#fields_names.sub(count), )*
148                }
149            }
150
151            /// Similar to [`*const T::wrapping_add()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add).
152            pub fn wrapping_add(self, count: usize) -> #ptr_name {
153                #ptr_name {
154                    #(#fields_names: self.#fields_names.wrapping_add(count), )*
155                }
156            }
157
158            /// Similar to [`*const T::wrapping_sub()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub).
159            pub fn wrapping_sub(self, count: usize) -> #ptr_name {
160                #ptr_name {
161                    #(#fields_names: self.#fields_names.wrapping_sub(count), )*
162                }
163            }
164
165            /// Similar to [`*const T::read()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.read),
166            /// with the same safety caveats.
167            pub unsafe fn read(self) -> #name {
168                #name {
169                    #(#fields_names: self.#fields_names.read(), )*
170                }
171            }
172
173            /// Similar to [`*const T::read_volatile()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.read_volatile),
174            /// with the same safety caveats.
175            pub unsafe fn read_volatile(self) -> #name {
176                #name {
177                    #(#fields_names: self.#fields_names.read_volatile(), )*
178                }
179            }
180
181            /// Similar to [`*const T::read_unaligned()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.read_unaligned),
182            /// with the same safety caveats.
183            pub unsafe fn read_unaligned(self) -> #name {
184                #name {
185                    #(#fields_names: self.#fields_names.read_unaligned(), )*
186                }
187            }
188        }
189
190        impl ::soa_derive::SoAPointers for #name {
191            type Ptr = #ptr_name;
192            type MutPtr = #ptr_mut_name;
193        }
194
195        #[allow(dead_code)]
196        #[allow(clippy::forget_non_drop)]
197        impl #ptr_mut_name {
198            /// Convert a
199            #[doc = #ptr_mut_doc_url]
200            /// to a
201            #[doc = #ptr_doc_url]
202            /// ; *i.e.* do a `*mut T as *const T` transformation
203            #visibility fn as_ptr(&self) -> #ptr_name {
204                #ptr_name {
205                    #( #fields_names: #as_ptr, )*
206                }
207            }
208
209            /// Similar to [`*mut T::is_null()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.is_null).
210            pub fn is_null(self) -> bool {
211                false #( || self.#fields_names.is_null())*
212            }
213
214            /// Similar to [`*mut T::as_ref()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref),
215            /// with the same safety caveats.
216            pub unsafe fn as_ref<'a>(self) -> Option<#ref_name<'a>> {
217                if self.is_null() {
218                    None
219                } else {
220                    Some(#ref_name {
221                        #(#fields_names: self.#fields_names.as_ref().expect("should not be null"), )*
222                    })
223                }
224            }
225
226            /// Similar to [`*mut T::as_mut()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.as_mut),
227            /// with the same safety caveats.
228            pub unsafe fn as_mut<'a>(self) -> Option<#ref_mut_name<'a>> {
229                if self.is_null() {
230                    None
231                } else {
232                    Some(#ref_mut_name {
233                        #(#fields_names: self.#fields_names.as_mut().expect("should not be null"), )*
234                    })
235                }
236            }
237
238            /// Similar to [`*mut T::offset()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.offset),
239            /// with the same safety caveats.
240            pub unsafe fn offset(self, count: isize) -> #ptr_mut_name {
241                #ptr_mut_name {
242                    #(#fields_names: self.#fields_names.offset(count), )*
243                }
244            }
245
246            /// Similar to [`*mut T::wrapping_offset()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset)
247            pub fn wrapping_offset(self, count: isize) -> #ptr_mut_name {
248                #ptr_mut_name {
249                    #(#fields_names: self.#fields_names.wrapping_offset(count), )*
250                }
251            }
252
253            /// Similar to [`*mut T::add()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.add),
254            /// with the same safety caveats.
255            pub unsafe fn add(self, count: usize) -> #ptr_mut_name {
256                #ptr_mut_name {
257                    #(#fields_names: self.#fields_names.add(count), )*
258                }
259            }
260
261            /// Similar to [`*mut T::sub()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.sub),
262            /// with the same safety caveats.
263            pub unsafe fn sub(self, count: usize) -> #ptr_mut_name {
264                #ptr_mut_name {
265                    #(#fields_names: self.#fields_names.sub(count), )*
266                }
267            }
268
269            /// Similar to [`*mut T::wrapping_add()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add),
270            /// with the same safety caveats.
271            pub fn wrapping_add(self, count: usize) -> #ptr_mut_name {
272                #ptr_mut_name {
273                    #(#fields_names: self.#fields_names.wrapping_add(count), )*
274                }
275            }
276
277            /// Similar to [`*mut T::wrapping_sub()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub),
278            /// with the same safety caveats.
279            pub fn wrapping_sub(self, count: usize) -> #ptr_mut_name {
280                #ptr_mut_name {
281                    #(#fields_names: self.#fields_names.wrapping_sub(count), )*
282                }
283            }
284
285            /// Similar to [`*mut T::read()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.read),
286            /// with the same safety caveats.
287            pub unsafe fn read(self) -> #name {
288                #name {
289                    #(#fields_names: self.#fields_names.read(), )*
290                }
291            }
292
293            /// Similar to [`*mut T::read_volatile()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.read_volatile),
294            /// with the same safety caveats.
295            pub unsafe fn read_volatile(self) -> #name {
296                #name {
297                    #(#fields_names: self.#fields_names.read_volatile(), )*
298                }
299            }
300
301            /// Similar to [`*mut T::read_unaligned()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.read_unaligned),
302            /// with the same safety caveats.
303            pub unsafe fn read_unaligned(self) -> #name {
304                #name {
305                    #(#fields_names: self.#fields_names.read_unaligned(), )*
306                }
307            }
308
309            /// Similar to [`*mut T::write()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.write),
310            /// with the same safety caveats.
311            #[allow(clippy::forget_non_drop)]
312            pub unsafe fn write(self, val: #name) {
313                unsafe {
314                    #(self.#fields_names.write(::std::ptr::read(&val.#fields_names));)*
315                }
316                // if val implements Drop, we don't want to run it here, only
317                // when the vec itself will be dropped
318                ::std::mem::forget(val);
319            }
320
321            /// Similar to [`*mut T::write_volatile()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.write_volatile),
322            /// with the same safety caveats.
323            #[allow(clippy::forget_non_drop)]
324            pub unsafe fn write_volatile(self, val: #name) {
325                unsafe {
326                    #(self.#fields_names.write_volatile(::std::ptr::read(&val.#fields_names));)*
327                }
328                // if val implements Drop, we don't want to run it here, only
329                // when the vec itself will be dropped
330                ::std::mem::forget(val);
331            }
332
333            /// Similar to [`*mut T::write_unaligned()`](https://doc.rust-lang.org/std/primitive.pointer.html#method.write_unaligned),
334            /// with the same safety caveats.
335            #[allow(clippy::forget_non_drop)]
336            pub unsafe fn write_unaligned(self, val: #name) {
337                unsafe {
338                    #(self.#fields_names.write_unaligned(::std::ptr::read(&val.#fields_names));)*
339                }
340                // if val implements Drop, we don't want to run it here, only
341                // when the vec itself will be dropped
342                ::std::mem::forget(val);
343            }
344        }
345
346        #[allow(dead_code)]
347        impl<'a> #ref_name<'a> {
348            /// Convert a
349            #[doc = #ref_doc_url]
350            /// to a
351            #[doc = #ptr_doc_url]
352            /// ; *i.e.* do a `&T as *const T` transformation
353            #visibility fn as_ptr(&self) -> #ptr_name {
354                #ptr_name {
355                    #( #fields_names: #as_ptr, )*
356                }
357            }
358        }
359
360        #[allow(dead_code)]
361        impl<'a> #ref_mut_name<'a> {
362            /// Convert a
363            #[doc = #ref_mut_doc_url]
364            /// to a
365            #[doc = #ptr_doc_url]
366            /// ; *i.e.* do a `&mut T as *const T` transformation
367            #visibility fn as_ptr(&self) -> #ptr_name {
368                #ptr_name {
369                    #( #fields_names: #as_ptr, )*
370                }
371            }
372
373            /// Convert a
374            #[doc = #ref_mut_doc_url]
375            /// to a
376            #[doc = #ptr_mut_doc_url]
377            /// ; *i.e.* do a `&mut T as *mut T` transformation
378            #visibility fn as_mut_ptr(&mut self) -> #ptr_mut_name {
379                #ptr_mut_name {
380                    #( #fields_names: #as_mut_ptr, )*
381                }
382            }
383        }
384    }
385}