Skip to content

Commit 8448c9f

Browse files
committed
Implement a pointer SoA type
1 parent 64ae02f commit 8448c9f

File tree

6 files changed

+551
-0
lines changed

6 files changed

+551
-0
lines changed

soa-derive-internal/src/input.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,12 @@ impl Input {
9797
pub fn ref_mut_name(&self) -> Ident {
9898
Ident::new(&format!("{}RefMut", self.name), Span::call_site())
9999
}
100+
101+
pub fn ptr_name(&self) -> Ident {
102+
Ident::new(&format!("{}Ptr", self.name), Span::call_site())
103+
}
104+
105+
pub fn ptr_mut_name(&self) -> Ident {
106+
Ident::new(&format!("{}PtrMut", self.name), Span::call_site())
107+
}
100108
}

soa-derive-internal/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use quote::TokenStreamExt;
1313
mod input;
1414
mod vec;
1515
mod refs;
16+
mod ptr;
1617
mod slice;
1718
mod iter;
1819

@@ -24,6 +25,7 @@ pub fn soa_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
2425
let mut generated = TokenStream::new();
2526
generated.append_all(vec::derive(&input));
2627
generated.append_all(refs::derive(&input));
28+
generated.append_all(ptr::derive(&input));
2729
generated.append_all(slice::derive_slice(&input));
2830
generated.append_all(slice::derive_slice_mut(&input));
2931
generated.append_all(iter::derive(&input));

soa-derive-internal/src/ptr.rs

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

0 commit comments

Comments
 (0)