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}