1#![deny(warnings)]
2#![doc(test(attr(deny(warnings))))]
3#![doc(test(attr(allow(dead_code))))]
4#![doc(test(attr(allow(unused_variables))))]
5#![allow(unknown_lints)]
6#![allow(clippy::mixed_attributes_style)]
7#![allow(clippy::needless_doctest_main)]
8
9#![no_std]
10
11#[doc=include_str!("../README.md")]
12type _DocTestReadme = ();
13
14#[doc(hidden)]
15pub use core::concat as std_concat;
16#[doc(hidden)]
17pub use core::ops::FnOnce as std_ops_FnOnce;
18#[doc(hidden)]
19pub use core::stringify as std_stringify;
20#[doc(hidden)]
21pub use generics::concat as generics_concat;
22#[doc(hidden)]
23pub use generics::parse as generics_parse;
24#[doc(hidden)]
25pub use indoc::indoc as indoc_indoc;
26#[doc(hidden)]
27pub use paste::paste as paste_paste;
28
29#[macro_export]
81macro_rules! free_lifetimes {
82 (
83 $(#[$attr:meta])*
84 $vis:vis struct $name:ident $($token:tt)*
85 ) => {
86 $crate::generics_parse! {
87 $crate::free_lifetimes_impl {
88 @struct [$([$attr])*] [$vis] [$name]
89 }
90 $($token)*
91 }
92 };
93}
94
95#[doc(hidden)]
96#[macro_export]
97macro_rules! free_lifetimes_impl {
98 (
99 @struct [$([$attr:meta])*] [$vis:vis] [$name:ident] [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
100 {
101 $($(
102 $field:ident : $($field_lt:lifetime)? $field_mod:ident $field_ty:ty
103 ),+ $(,)?)?
104 }
105 ) => {
106 $crate::free_lifetimes_impl! {
107 @impl struct
108 [$name] [$([$attr])*] [$vis] [ty] [this] [builder]
109 [$($g)*] [$($r)*] [$($w)*]
110 [] [] [] [] []
111 [$($([$field : $($field_lt)? $field_mod $field_ty])+)?]
112 }
113 };
114 (
115 @struct [$([$attr:meta])*] [$vis:vis] [$name:ident] [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
116 $($body:tt)*
117 ) => {
118 $crate::std_compile_error!($crate::indoc_indoc!("
119 invalid free lifetimes struct definition, allowed form is
120
121 $(#[$attr:meta])*
122 $vis:vis struct $name:ident $(<$generics> $(where $where_clause)?)? {
123 $($(
124 $field:ident : $($lt:lifetime ref | $lt:lifetime mut | const) $ty:ty
125 ),+ $(,)?)?
126 }
127
128 "));
129 };
130 (
131 @impl struct
132 [$name:ident] [$([$attr:meta])*] [$vis:vis] [$ty:ident] [$this:ident] [$builder:ident]
133 [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
134 [$($builder_lts:tt)*]
135 [$($builder_fields:tt)*]
136 [$($struct_fields:tt)*]
137 [$($ctor_assignments:tt)*]
138 [$($struct_methods:tt)*]
139 [[$field:ident : $field_lt:lifetime ref $field_ty:ty] $($other_fields:tt)*]
140 ) => {
141 $crate::free_lifetimes_impl! {
142 @impl struct [$name] [$([$attr])*] [$vis] [$ty] [$this] [$builder] [$($g)*] [$($r)*] [$($w)*]
143 [
144 $($builder_lts)*
145 [$field_lt]
146 ]
147 [
148 $($builder_fields)*
149 pub $field : & $field_lt $field_ty,
150 ]
151 [
152 $($struct_fields)*
153 $field : &'static $field_ty,
154 ]
155 [
156 $($ctor_assignments)*
157 $field : unsafe { &*($builder . $field as *const $field_ty) },
158 ]
159 [
160 $($struct_methods)*
161 $vis fn $field (&self) -> &$field_ty { self.$field }
162 ]
163 [$($other_fields)*]
164 }
165 };
166 (
167 @impl struct
168 [$name:ident] [$([$attr:meta])*] [$vis:vis] [$ty:ident] [$this:ident] [$builder:ident]
169 [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
170 [$($builder_lts:tt)*]
171 [$($builder_fields:tt)*]
172 [$($struct_fields:tt)*]
173 [$($ctor_assignments:tt)*]
174 [$($struct_methods:tt)*]
175 [[$field:ident : $field_lt:lifetime mut $field_ty:ty] $($other_fields:tt)*]
176 ) => {
177 $crate::free_lifetimes_impl! {
178 @impl struct [$name] [$([$attr])*] [$vis] [$ty] [$this] [$builder] [$($g)*] [$($r)*] [$($w)*]
179 [
180 $($builder_lts)*
181 [$field_lt]
182 ]
183 [
184 $($builder_fields)*
185 pub $field : & $field_lt mut $field_ty,
186 ]
187 [
188 $($struct_fields)*
189 $field : &'static mut $field_ty,
190 ]
191 [
192 $($ctor_assignments)*
193 $field : unsafe { &mut *($builder . $field as *mut $field_ty) },
194 ]
195 [
196 $($struct_methods)*
197
198 #[allow(dead_code)]
199 $vis fn $field (&self) -> &$field_ty { self.$field }
200
201 #[allow(dead_code)]
202 $vis fn [< $field _mut >] (&mut self) -> &mut $field_ty { self.$field }
203 ]
204 [$($other_fields)*]
205 }
206 };
207 (
208 @impl struct
209 [$name:ident] [$([$attr:meta])*] [$vis:vis] [$ty:ident] [$this:ident] [$builder:ident]
210 [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
211 [$($builder_lts:tt)*]
212 [$($builder_fields:tt)*]
213 [$($struct_fields:tt)*]
214 [$($ctor_assignments:tt)*]
215 [$($struct_methods:tt)*]
216 [[$field:ident : const $field_ty:ty] $($other_fields:tt)*]
217 ) => {
218 $crate::free_lifetimes_impl! {
219 @impl struct [$name] [$([$attr])*] [$vis] [$ty] [$this] [$builder] [$($g)*] [$($r)*] [$($w)*]
220 [$($builder_lts)*]
221 [
222 $($builder_fields)*
223 pub $field : $field_ty,
224 ]
225 [
226 $($struct_fields)*
227 $field : $field_ty,
228 ]
229 [
230 $($ctor_assignments)*
231 $field: $builder . $field,
232 ]
233 [
234 $($struct_methods)*
235 $vis fn $field (&self) -> $field_ty { self.$field }
236 ]
237 [$($other_fields)*]
238 }
239 };
240 (
241 @impl struct
242 [$name:ident] [$([$attr:meta])*] [$vis:vis] [$ty:ident] [$this:ident] [$builder:ident]
243 [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
244 [$($builder_lts:tt)*]
245 [$($builder_fields:tt)*]
246 [$($struct_fields:tt)*]
247 [$($ctor_assignments:tt)*]
248 [$($struct_methods:tt)*]
249 [[$field:ident : $($field_lt:lifetime)? $field_mod:ident $field_ty:ty] $($other_fields:tt)*]
250 ) => {
251 $crate::std_compile_error!($crate::std_concat!(
252 "invalid free lifetimes struct field '",
253 $crate::std_stringify!($field : $($field_lt)? $field_mod $field_ty),
254 "\
255 ', allowed form is '\
256 $field:ident : $($lt:lifetime ref | $lt:lifetime mut | const) $ty:ty\
257 '\
258 ",
259 ));
260 };
261 (
262 @impl struct
263 [$name:ident] [$([$attr:meta])*] [$vis:vis] [$ty:ident] [$this:ident] [$builder:ident]
264 [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
265 [$($([$builder_lts:tt])+)?]
266 [$($builder_fields:tt)*]
267 [$($struct_fields:tt)*]
268 [$($ctor_assignments:tt)*]
269 [$($struct_methods:tt)*]
270 []
271 ) => {
272 $crate::generics_concat! {
273 $crate::free_lifetimes_impl {
274 @impl [$name] [$([$attr])*] [$vis] [$ty] [$this] [$builder] [$($g)*] [$($r)*] [$($w)*]
275 [$($builder_fields)*]
276 [$($struct_fields)*]
277 [$($ctor_assignments)*]
278 [$($struct_methods)*]
279 }
280 [$( < $($builder_lts),+ > )?] [$( < $($builder_lts),+ > )?] [],
281 [$($g)*] [$($r)*] [$($w)*]
282 }
283 };
284 (
285 @impl
286 [$name:ident] [$([$attr:meta])*] [$vis:vis] [$ty:ident] [$this:ident] [$builder:ident]
287 [$($g:tt)*] [$($r:tt)*] [$($w:tt)*]
288 [$($builder_fields:tt)*]
289 [$($struct_fields:tt)*]
290 [$($ctor_assignments:tt)*]
291 [$($struct_methods:tt)*]
292 [$($builder_g:tt)*] [$($builder_r:tt)*] [$($builder_w:tt)*]
293 ) => {
294 $crate::paste_paste! {
295 $vis struct [< $name Builder >] $($builder_g)* $($w)* {
296 $($builder_fields)*
297 }
298
299 impl $($builder_g)* [< $name Builder >] $($builder_r)* $($builder_w)* {
300 $vis fn build_and_then<FreeLifetimesStructBuildReturnType>(
303 &mut self,
304 f: impl $crate::std_ops_FnOnce(&mut $name $($r)*) -> FreeLifetimesStructBuildReturnType
305 ) -> FreeLifetimesStructBuildReturnType {
306 let $builder = self;
307 let mut free_lifetimes = $name {
308 $($ctor_assignments)*
309 };
310 f(&mut free_lifetimes)
311 }
312 }
313
314 $(#[$attr])*
315 $vis struct $name $($g)* $($w)* {
316 $($struct_fields)*
317 }
318
319 impl $($g)* $name $($r)* $($w)* {
320 $($struct_methods)*
321 }
322 }
323 };
324}
325
326#[cfg(docsrs)]
327pub mod example {
328 pub struct Data {
342 pub x: i16,
343 pub y: i16
344 }
345
346 free_lifetimes! {
347 pub struct FreeLifetimesStruct {
348 data: 'data mut Data,
349 str_data: 'str_data ref str,
350 id: const usize,
351 }
352 }
353}
354
355#[cfg(test)]
356mod test {
357 use core::mem::replace;
358 use core::ops::Deref;
359
360 free_lifetimes! {
361 struct State1 {
362 a: const u8,
363 b: 'b ref u16,
364 c: 'c mut u32,
365 }
366 }
367
368 #[test]
369 fn test_state_1() {
370 let mut x = 3;
371 let res = State1Builder {
372 a: 1,
373 b: &2,
374 c: &mut x
375 }.build_and_then(|state| {
376 assert_eq!(state.a(), 1u8);
377 assert_eq!(state.b(), &2u16);
378 assert_eq!(replace(state.c_mut(), 12), 3u32);
379 "res"
380 });
381 assert_eq!(res, "res");
382 assert_eq!(x, 12);
383 }
384
385 #[test]
386 fn test_state_1_const() {
387 let mut x = 3;
388 let res = State1Builder {
389 a: 1,
390 b: &2,
391 c: &mut x
392 }.build_and_then(|state| {
393 assert_eq!(state.a(), 1u8);
394 assert_eq!(state.b(), &2u16);
395 assert_eq!(state.c(), &3u32);
396 "res"
397 });
398 assert_eq!(res, "res");
399 assert_eq!(x, 3);
400 }
401
402 #[allow(dead_code)]
403 #[derive(Debug, Clone, Copy)]
404 struct PrivStr;
405
406 free_lifetimes! {
407 #[derive(Debug)]
408 pub struct Items<ItemType: 'static> {
409 items: 'items ref [ItemType],
410 }
411 }
412
413 impl<ItemType> Deref for Items<ItemType> {
414 type Target = [ItemType];
415
416 fn deref(&self) -> &Self::Target {
417 self.items()
418 }
419 }
420
421 #[test]
422 fn free_lifetimes_with_generics() {
423 let items = &[1, 2, 3];
424 let sum: u8 = ItemsBuilder {
425 items
426 }.build_and_then(|items| {
427 items.iter().sum()
428 });
429 assert_eq!(sum, 6);
430 }
431}