1#![feature(ptr_metadata)]
4
5use std::ptr::NonNull;
6
7mod basic_impls;
8mod projection;
9pub use projection::*;
10mod place_ops;
11pub use place_ops::*;
12
13#[macro_export]
18macro_rules! mk_field_proj {
19 (struct $name:ident($src_ty:ident.$field:ident: $tgt_ty:ty)) => {
20 #[derive(Clone)]
21 struct $name;
22 impl Projection for $name {
23 type Source = $src_ty;
24 type Target = $tgt_ty;
25 fn offset(
26 &self,
27 _: <Self::Source as core::ptr::Pointee>::Metadata,
28 ) -> usize {
29 core::mem::offset_of!($src_ty, $field)
30 }
31 fn project_metadata(
32 &self,
33 _: <Self::Source as core::ptr::Pointee>::Metadata,
34 ) -> <Self::Target as core::ptr::Pointee>::Metadata {
35 }
36 }
37 };
38}
39
40#[macro_export]
64macro_rules! p {
65 (#parse_base(
69 $action:ident($($action_args:tt)*),
70 input(
71 (*$($place:tt)*)
73 $($rest:tt)*
74 )
75 )) => {{
76 use $crate::ProjectionExt;
77 let start = p!(#build_start(deref($($place)*)));
78 $crate::p!(#parse_proj(
79 $action($($action_args)*),
80 ptr(start),
81 project(),
82 input($($rest)*)
83 ))
84 }};
85 (#parse_base(
86 $action:ident($($action_args:tt)*),
87 input(
88 *$local:ident
90 )
91 )) => {
92 $crate::p!(#parse_base(
93 $action($($action_args)*),
94 input($local.*)
95 ))
96 };
97 (#parse_base(
98 $action:ident($($action_args:tt)*),
99 input(
100 $local:ident.*
102 $($rest:tt)*
103 )
104 )) => {
105 $crate::p!(#parse_proj(
106 $action($($action_args)*),
107 ptr(&raw const $local),
108 project(),
109 input($($rest)*)
110 ))
111 };
112 (#parse_base(
113 $action:ident($($action_args:tt)*),
114 input(
115 ($($place:tt)*)
117 $($rest:tt)*
118 )
119 )) => {
120 $crate::p!(#parse_base(
121 $action($($action_args)*),
122 input($($place)* $($rest)*)
123 ))
124 };
125 (#parse_proj(
142 $action:ident($($action_args:tt)*),
143 $start:ident($($start_args:tt)*),
144 project($($fields:tt)*),
145 input(
146 . * $($input:tt)*
148 )
149 )) => {{
150 let p = $crate::p!(#parse_proj(
152 deref(),
153 $start($($start_args)*),
154 project($($fields)*),
155 input()
156 ));
157 $crate::p!(#parse_proj(
158 $action($($action_args)*),
159 ptr(p),
160 project(),
161 input($($input)*)
162 ))
163 }};
164 (#parse_proj(
165 $action:ident($($action_args:tt)*),
166 $start:ident($($start_args:tt)*),
167 project($($fields:tt)*),
168 input(
169 .$field:ident
170 $($rest:tt)*
171 )
172 )) => {
173 $crate::p!(#parse_proj(
174 $action($($action_args)*),
175 $start($($start_args)*),
176 project($($fields)*.$field),
177 input($($rest)*)
178 ))
179 };
180 (#parse_proj(
181 $action:ident($($action_args:tt)*),
182 $start:ident($($start_args:tt)*),
183 project($($fields:tt)*),
184 input(
185 $(= $rvalue:expr)?
186 )
187 )) => {
188 $crate::p!(#parse_assign(
189 $action($($action_args)*),
190 $start($($start_args)*),
191 project($($fields)*),
192 input($(= $rvalue)?)
193 ))
194 };
195 (#parse_assign(
197 read_or_write(),
198 $start:ident($($start_args:tt)*),
199 project($($proj_args:tt)*),
200 input(
201 = $rvalue:expr
202 )
203 )) => {
204 $crate::p!(#build(
205 write($rvalue),
206 $start($($start_args)*),
207 project($($proj_args)*),
208 ))
209 };
210 (#parse_assign(
211 read_or_write(),
212 $start:ident($($start_args:tt)*),
213 project($($proj_args:tt)*),
214 input()
215 )) => {
216 $crate::p!(#build(
217 read(),
218 $start($($start_args)*),
219 project($($proj_args)*),
220 ))
221 };
222 (#parse_assign(
223 $action:ident($($action_args:tt)*),
224 $start:ident($($start_args:tt)*),
225 project($($proj_args:tt)*),
226 input()
227 )) => {
228 $crate::p!(#build(
229 $action($($action_args)*),
230 $start($($start_args)*),
231 project($($proj_args)*),
232 ))
233 };
234
235 (#compose_projs()) => { $crate::NoopProj::default() };
238 (#compose_projs(.$field:ident $($rest:tt)*)) => {
239 $field.compose(p!(#compose_projs($($rest)*)))
240 };
241 (#build_start(deref($ptr:ident))) => { &raw const $ptr };
244 (#build_start(deref($($place:tt)*))) => {
245 $crate::p!(#parse_base(deref(), input($($place)*)))
246 };
247
248 (#build(
250 $action:ident($($action_args:tt)*),
251 ptr($ptr:expr),
252 project($($proj_args:tt)*),
253 )) => {{
254 use $crate::ProjectionExt;
255 let proj = p!(#compose_projs($($proj_args)*));
256 $crate::p!(#do_action(
257 $action($($action_args)*),
258 base($ptr),
259 project(proj),
260 ))
261 }};
262
263 (#do_action(
265 read(),
266 base($ptr:expr),
267 project($proj:expr),
268 )) => {
269 $proj.read($ptr)
270 };
271 (#do_action(
272 deref(),
273 base($ptr:expr),
274 project($proj:expr),
275 )) => {
276 $proj.deref($ptr.cast_mut())
277 };
278 (#do_action(
279 write($rvalue:expr),
280 base($ptr:expr),
281 project($proj:expr),
282 )) => {
283 $proj.write($ptr.cast_mut(), $rvalue)
284 };
285 (#do_action(
286 borrow($($ptr_ty:tt)*),
287 base($ptr:expr),
288 project($proj:expr),
289 )) => {
290 $proj.borrow::<_, $($ptr_ty)*>($ptr)
291 };
292
293 (#$($rest:tt)*) => {
296 compile_error!("Unsupported expression")
297 };
298
299 (@_ $($place:tt)*) => {
302 $crate::p!(#parse_base(borrow(_), input($($place)*)))
303 };
304 (@$ptr:ident<$($ty:ty),*> $($place:tt)*) => {
306 $crate::p!(#parse_base(borrow($ptr<$($ty),*>), input($($place)*)))
307 };
308 (@$ptr:ident $($place:tt)*) => {
310 $crate::p!(#parse_base(borrow($ptr<_>), input($($place)*)))
311 };
312 ($($place:tt)*) => {
314 $crate::p!(#parse_base(read_or_write(), input($($place)*)))
315 };
316}