1pub use self::marker::*;
29pub use core::marker::PhantomData;
30
31pub mod marker;
32
33pub struct Uninit {
35 __private: ()
36}
37
38pub struct Init<T = (), M = ()>
42where
43 T: ?Sized,
44 M: ?Sized + TypeMarker
45{
46 __marker_t: PhantomDataInvariant<T>,
48 __marker_g: PhantomDataInvariant<M>
49}
50
51pub unsafe trait InitStatus {
64 const IS_INIT: bool;
65 const IS_UNINIT: bool = !Self::IS_INIT;
66}
67
68unsafe impl InitStatus for Uninit {
70 const IS_INIT: bool = false;
71}
72
73unsafe impl<T, M> InitStatus for Init<T, M>
75where
76 T: ?Sized,
77 M: ?Sized + TypeMarker
78{
79 const IS_INIT: bool = true;
80}
81
82#[diagnostic::on_unimplemented(
88 message = "this field has already been initialised"
89)]
90pub unsafe trait IsUninit: InitStatus {}
91
92unsafe impl IsUninit for Uninit {}
94
95pub unsafe trait IsInit: InitStatus {}
101
102unsafe impl<T> IsInit for Init<T>
104where
105 T: ?Sized
106{}
107
108pub unsafe trait Slot<S>
113where
114 Self: Sized
115{
116 type TypeMarker: TypeMarker;
117
118 type Result: Sized;
120
121 unsafe fn write(self, slot: &mut S);
138
139 unsafe fn read(slot: S) -> Self::Result;
152
153 fn as_ref(result: &Self::Result) -> &crate::ExternAny;
161}
162
163pub(crate) type PhantomDataBuilder<S> = PhantomData<(
169 fn(S) -> S,
171 *mut ()
173)>;
174
175pub(crate) type PhantomDataInvariant<T> = PhantomData<fn(T) -> T>;
181
182macro_rules! gen_struct {
183 {
184 $(#[$meta:meta])*
185 struct $struct_name_without_state:ident $struct_name:ident;
187
188 $(
190 deref $deref_type:ty;
191 deref_value $deref_value:expr;
193 )?
194
195 $(untracked_deref $untracked_field_deref:ident: $untracked_field_deref_type:ty;)?
198
199 $(
200 field
201 $field:ident
203 $slot:ident;
205 )*
206
207 $(untracked_field $untracked_field:ident: $untracked_field_type:ty;)*
208 } => {
209 pub type $struct_name_without_state = $struct_name<'static, StateUninit>;
210
211 #[repr(transparent)]
212 pub struct $struct_name<'h, S: State> {
213 inner: Inner<'h>,
214 __marker: PhantomDataBuilder<S>
215 }
216
217 struct Inner<'h> {
218 __use_h: PhantomData<&'h ()>,
219 $(__deref: ::core::cell::UnsafeCell<::core::option::Option<$deref_type>>,)?
220 $($field: $slot<'h>,)*
221 $($untracked_field: $untracked_field_type),*
222 }
223
224 impl $struct_name<'static, StateUninit> {
225 #[inline(always)]
231 const unsafe fn __new(
232 $($untracked_field: $untracked_field_type),*
233 ) -> Self {
234 Self {
235 inner: Inner {
236 __use_h: PhantomData,
237 $(__deref: ::core::cell::UnsafeCell::new(None::<$deref_type>),)?
240 $($field: $slot::uninit(),)*
241 $($untracked_field),*
242 },
243 __marker: PhantomData
244 }
245 }
246 }
247
248 $(
249 impl<'h, S> ::core::ops::Deref for $struct_name<'h, S>
250 where
251 S: State
252 {
253 type Target = $deref_type;
254
255 #[inline(always)]
256 fn deref(&self) -> &$deref_type {
257 unsafe {
262 (*self.inner.__deref.get())
263 .get_or_insert_with(|| $deref_value)
264 }
265 }
266 }
267 )?
268
269 $(
270 impl<'h, S> ::core::ops::Deref for $struct_name<'h, S>
271 where
272 S: State
273 {
274 type Target = $untracked_field_deref_type;
275
276 #[inline(always)]
277 fn deref(&self) -> &$untracked_field_deref_type {
278 &self.inner.$untracked_field_deref
279 }
280 }
281 )?
282 };
283}
284pub(crate) use gen_struct;
285
286macro_rules! gen_slot {
287 {
288 $(#[$meta:meta])*
289 slot $slot:ident;
291 $(
292 field
293 $field:ident
295 $field_type:ty;
297 )*
298 } => {
299 $(#[$meta])*
300 pub union $slot<'h> {
301 uninit: (),
302 any: &'h ExternAny,
303 $($field: ::core::mem::ManuallyDrop<$field_type>),*
304 }
305
306 impl $slot<'static> {
307 #[inline(always)]
308 pub(crate) const fn uninit() -> Self {
309 Self { uninit: () }
311 }
312 }
313 };
314}
315pub(crate) use gen_slot;
316
317macro_rules! gen_slot_impl {
318 {
320 $(#[$meta:meta])*
321 slot $slot:ident;
322 impl$({ $($generics:tt)* })? $impl_type:ty;
323
324 $($stuff:tt)*
325 } => {
326 unsafe impl<'h $(, $($generics)*)?> Slot<$slot<'h>> for $impl_type {
327 gen_slot_impl! {
328 @impl
329 slot $slot;
330 impl $impl_type;
331
332 $($stuff)*
333 }
334 }
335 };
336
337 {
339 @impl
340 slot $slot:ident;
341 impl $impl_type:ty;
342
343 result $result_type:ty;
344
345 $($stuff:tt)*
346 } => {
347 type Result = $result_type;
348
349 gen_slot_impl! {
350 @impl
351 slot $slot;
352 impl $impl_type;
353
354 $($stuff)*
355 }
356 };
357
358 {
360 @impl
361 slot $slot:ident;
362 impl $impl_type:ty;
363
364 no_type_marker;
365
366 $($stuff:tt)*
367 } => {
368 type TypeMarker = ();
369
370 gen_slot_impl! {
371 @impl
372 slot $slot;
373 impl $impl_type;
374
375 $($stuff)*
376 }
377 };
378
379 {
381 @impl
382 slot $slot:ident;
383 impl $impl_type:ty;
384
385 type_marker $type_marker:ty;
386
387 $($stuff:tt)*
388 } => {
389 type TypeMarker = $type_marker;
390
391 gen_slot_impl! {
392 @impl
393 slot $slot;
394 impl $impl_type;
395
396 $($stuff)*
397 }
398 };
399
400 {
401 @impl
402 slot $slot:ident;
403 impl $impl_type:ty;
404
405 no_type_marker;
406
407 $($stuff:tt)*
408 } => {
409 type TypeMarker = ();
410
411 gen_slot_impl! {
412 @impl
413 slot $slot;
414 impl $impl_type;
415
416 $($stuff)*
417 }
418 };
419
420 {
422 @impl
423 slot $slot:ident;
424 impl $impl_type:ty;
425
426 write($self:ident, $write_slot:ident) {
427 $($write_impl:tt)*
428 }
429
430 $($stuff:tt)*
431 } => {
432 #[inline(always)]
433 unsafe fn write($self, $write_slot: &mut $slot<'h>) {
434 $($write_impl)*
435 }
436
437 gen_slot_impl! {
438 @impl
439 slot $slot;
440 impl $impl_type;
441
442 $($stuff)*
443 }
444 };
445
446 {
448 @impl
449 slot $slot:ident;
450 impl $impl_type:ty;
451
452 read($read_slot:ident) {
453 $($read_impl:tt)*
454 }
455
456 $($stuff:tt)*
457 } => {
458 #[inline(always)]
459 unsafe fn read($read_slot: $slot<'h>) -> Self::Result {
460 $($read_impl)*
461 }
462
463 gen_slot_impl! {
464 @impl
465 slot $slot;
466 impl $impl_type;
467
468 $($stuff)*
469 }
470 };
471
472 {
474 @impl
475 slot $slot:ident;
476 impl $impl_type:ty;
477
478 as_ref($as_ref_result:ident) {
479 $($as_ref_impl:tt)*
480 }
481
482 $($stuff:tt)*
483 } => {
484 #[inline(always)]
485 fn as_ref($as_ref_result: &Self::Result) -> &ExternAny {
486 $($as_ref_impl)*
487 }
488
489 gen_slot_impl! {
490 @impl
491 slot $slot;
492 impl $impl_type;
493
494 $($stuff)*
495 }
496 };
497
498 {
502 @impl
503 slot $slot:ident;
504 impl $impl_type:ty;
505
506 simple_w $field:ident;
507
508 $($stuff:tt)*
509 } => {
510 gen_slot_impl! {
511 @impl
512 slot $slot;
513 impl $impl_type;
514
515 write(self, slot) {
516 *slot = $slot { $field: self }
517 }
518
519 $($stuff)*
520 }
521 };
522
523 {
526 @impl
527 slot $slot:ident;
528 impl $impl_type:ty;
529
530 simple_rw $field:ident;
531
532 $($stuff:tt)*
533 } => {
534 gen_slot_impl! {
535 @impl
536 slot $slot;
537 impl $impl_type;
538
539 simple_w $field;
540
541 read(slot) {
542 unsafe { slot.$field }
543 }
544
545 $($stuff)*
546 }
547 };
548
549 {
552 @impl
553 slot $slot:ident;
554 impl $impl_type:ty;
555
556 autoderef;
557
558 $($stuff:tt)*
559 } => {
560 gen_slot_impl! {
561 @impl
562 slot $slot;
563 impl $impl_type;
564
565 as_ref(result) { result }
566
567 $($stuff)*
568 }
569 };
570
571 {
572 @impl
573 slot $slot:ident;
574 impl $impl_type:ty;
575 } => { };
576}
577pub(crate) use gen_slot_impl;
578
579macro_rules! unsafe_read_slots {
614 {
615 $self:ident
616 $($ident:ident: $ty:ident)*
617 } => {
618 $(
619 let $ident = unsafe { $ty::read($self.inner.$ident) };
621 let $ident = $ty::as_ref(&$ident).as_js_value();
622 )*
623 }
624}
625pub(crate) use unsafe_read_slots;
626
627macro_rules! gen_state {
628 {
629 $(
630 $(#[$state_meta:meta])*
631 state
632 )?
633
634 $(
635 $(#[$container_meta:meta])*
636 container
637 )?
638
639 $(
640 $(#[$uninit_meta:meta])*
641 uninit
642 )?
643
644 $(
645 field $field:ident;
646 init $field_init:ident;
647 )*
648 } => {
649 $($(#[$state_meta])*)?
650 pub trait State {
651 $(
652 type $field: InitStatus;
653 type $field_init<T: ?Sized, M: ?Sized + TypeMarker>: State;
654 )*
655 }
656
657 #[allow(
658 unused_parens,
659 reason = "automatically generated"
660 )]
661 #[expect(
662 clippy::allow_attributes,
663 reason = "automatically generated (lint might not actually trigger, depending on input)"
664 )]
665 $($(#[$container_meta])*)?
666 pub struct StateContainer<$($field),*> {
667 __marker: PhantomDataInvariant<(
668 $($field),*
669 )>
670 }
671
672 gen_state! {
673 @impl gen_uninit
674 $(
675 $(#[$uninit_meta])*
676 uninit
677 )?
678
679 {}
680 { $($field)* }
681 }
682
683 impl<$(
684 $field: InitStatus
685 ),*> State for StateContainer<$($field),*> {
686 gen_state! {
687 @impl state_init_types
688 {}
689 {}
690 { $($field $field_init)* }
691 }
692 }
693 };
694
695 {
696 @impl gen_uninit
697 $(
698 $(#[$uninit_meta:meta])*
699 uninit
700 )?
701
702 { $($uninit_type:ident)* }
703 {
704 $field:ident
705 $($field_rest:ident)*
706 }
707 } => {
708 gen_state! {
709 @impl gen_uninit
710 $(
711 $(#[$uninit_meta])*
712 uninit
713 )?
714
715 {
716 $($uninit_type)*
717 Uninit
718 }
719 { $($field_rest)* }
720 }
721 };
722
723 {
724 @impl gen_uninit
725 $(
726 $(#[$uninit_meta:meta])*
727 uninit
728 )?
729
730 { $($uninit_type:ident)* }
731 {}
732 } => {
733 pub type StateUninit = StateContainer<
734 $($uninit_type),*
735 >;
736 };
737
738 {
739 @impl state_init_types
740 {}
741 {}
742 {}
743 } => {};
744
745 {
746 @impl state_init_types
747 {}
748 {}
749 {
750 $field_next:ident $field_init_next:ident
751 $($field_rest:ident $field_init_rest:ident)*
752 }
753 } => {
754 gen_state! {
755 @impl state_init_types
756 {}
757 { $field_next $field_init_next }
758 { $($field_rest $field_init_rest)* }
759 }
760 };
761
762 {
763 @impl state_init_types
764 { $($field_prev:ident $field_init_prev:ident)* }
765 { $field:ident $field_init:ident }
766 {
767 $field_next:ident $field_init_next:ident
768 $($field_rest:ident $field_init_rest:ident)*
769 }
770 } => {
771 type $field = $field;
772 type $field_init<T: ?Sized, M: ?Sized + TypeMarker> = StateContainer<
773 $($field_prev,)*
774 Init<T, M>,
775 $field_next,
776 $($field_rest),*
777 >;
778
779 gen_state! {
780 @impl state_init_types
781 {
782 $($field_prev $field_init_prev)*
783 $field $field_init
784 }
785 { $field_next $field_init_next }
786 { $($field_rest $field_init_rest)* }
787 }
788 };
789
790 {
791 @impl state_init_types
792 { $($field_prev:ident $field_init_prev:ident)* }
793 { $field:ident $field_init:ident }
794 {}
795 } => {
796 type $field = $field;
797 type $field_init<T: ?Sized, M: ?Sized + TypeMarker> = StateContainer<
798 $($field_prev,)*
799 Init<T, M>
800 >;
801 };
802}
803pub(crate) use gen_state;
804
805macro_rules! gen_builder_fns {
806 {
807 struct $struct_name:ident;
808
809 $(
810 state $field_state:ident;
811 init $field_init:ident;
812 slot $slot:ident;
813 $(extra_bounds { $($extra_bounds:tt)* };)?
814
815 $(#[$meta:meta])*
816 field $field:ident $($no_lifetime:ident)?;
817 )*
818 } => {
819 impl<'h, S: State> $struct_name<'h, S> {
820 gen_change_state!($struct_name);
821
822 $(
823 gen_builder_fn! {
824 struct $struct_name;
825
826 state $field_state;
827 init $field_init;
828 slot $slot;
829 $(extra_bounds { $($extra_bounds)* };)?
830
831 $(#[$meta:meta])*
832 field $field $($no_lifetime)?;
833 }
834 )*
835 }
836 }
837}
838pub(crate) use gen_builder_fns;
839
840macro_rules! gen_builder_fn {
841 {
842 struct $struct_name:ident;
843
844 state $field_state:ident;
845 init $field_init:ident;
846 slot $slot:ident;
847 $(extra_bounds { $($extra_bounds:tt)* };)?
848
849 $(#[$meta:meta])*
850 field $field:ident;
851 } => {
852 #[inline(always)]
853 $(#[$meta])*
854 pub fn $field<T>(
855 self,
856 $field: T
857 ) -> $struct_name<'h, S::$field_init<T, T::TypeMarker>>
858 where
859 S::$field_state: IsUninit,
860 T: Slot<$slot<'h>>,
861 $($($extra_bounds)*)?
862 {
863 unsafe { self.change_state(|b| $field.write(&mut b.inner.$field)) }
864 }
865 };
866}
867pub(crate) use gen_builder_fn;
868
869macro_rules! gen_change_state {
870 ($struct_name:ident) => {
871 #[inline(always)]
872 unsafe fn change_state<'h2, S2, F>(self, f: F) -> $struct_name<'h2, S2>
873 where
874 'h: 'h2,
875 S2: State,
876 F: FnOnce(&mut $struct_name<'h2, S2>)
877 {
878 let mut changed = $struct_name {
879 inner: self.inner,
880 __marker: PhantomData
881 };
882
883 f(&mut changed);
884 changed
885 }
886 };
887}
888pub(crate) use gen_change_state;
889
890macro_rules! gen_call_fn {
891 {
892 struct $struct_name:ident;
893 raw_call $raw_call:expr;
894 return $return_type:ty;
895
896 $($rest:tt)*
897 } => {
898 gen_call_fn! {
899 @impl nom_fields
900 struct $struct_name;
901 raw_call $raw_call;
902 return $return_type;
903
904 fn_name call_fn;
905
906 fields {}
907
908 $($rest)*
909 }
910 };
911
912 {
913 @impl nom_fields
914 struct $struct_name:ident;
915 raw_call $raw_call:expr;
916 return $return_type:ty;
917
918 $(#[$meta:meta])*
919 fn_name $fn_name:ident;
920
921 fields { $($fields:tt)* }
922
923 field $field_name:ident;
924 state $field_state:ident;
925 init Init<$slot:ident>;
926
927 $($stuff:tt)*
928 } => {
929 gen_call_fn! {
930 @impl nom_fields
931 struct $struct_name;
932 raw_call $raw_call;
933 return $return_type;
934
935 $(#[$meta])*
936 fn_name $fn_name;
937
938 fields {
939 $($fields)*
940
941 field
942 { $field_state: Slot<$slot<'h>>, }
943 { Init<$field_state> }
944 { $field_name: $field_state }
945 {}
946 }
947
948 $($stuff)*
949 }
950 };
951
952 {
953 @impl nom_fields
954 struct $struct_name:ident;
955 raw_call $raw_call:expr;
956 return $return_type:ty;
957
958 $(#[$meta:meta])*
959 fn_name $fn_name:ident;
960
961 fields { $($fields:tt)* }
962
963 field $field_name:ident;
964 state $field_state:ident;
965 init Init<$slot:ident, $general_type:ty>;
966
967 $($stuff:tt)*
968 } => {
969 gen_call_fn! {
970 @impl nom_fields
971 struct $struct_name;
972 raw_call $raw_call;
973 return $return_type;
974
975 $(#[$meta])*
976 fn_name $fn_name;
977
978 fields {
979 $($fields)*
980
981 field
982 { $field_state: Slot<$slot<'h>>, }
983 { Init<$field_state, $general_type> }
984 { $field_name: $field_state }
985 {}
986 }
987
988 $($stuff)*
989 }
990 };
991
992 {
993 @impl nom_fields
994 struct $struct_name:ident;
995 raw_call $raw_call:expr;
996 return $return_type:ty;
997
998 $(#[$meta:meta])*
999 fn_name $fn_name:ident;
1000
1001 fields { $($fields:tt)* }
1002
1003 field $field_name:ident;
1004 state $field_state:ident;
1005 init Init<$slot:ident, any $general_type:ident>;
1006
1007 $($stuff:tt)*
1008 } => {
1009 gen_call_fn! {
1010 @impl nom_fields
1011 struct $struct_name;
1012 raw_call $raw_call;
1013 return $return_type;
1014
1015 $(#[$meta])*
1016 fn_name $fn_name;
1017
1018 fields {
1019 $($fields)*
1020
1021 field
1022 { $field_state: Slot<$slot<'h>>, $general_type: TypeMarker, }
1023 { Init<$field_state, $general_type> }
1024 { $field_name: $field_state }
1025 {}
1026 }
1027
1028 $($stuff)*
1029 }
1030 };
1031
1032 {
1033 @impl nom_fields
1034 struct $struct_name:ident;
1035 raw_call $raw_call:expr;
1036 return $return_type:ty;
1037
1038 $(#[$meta:meta])*
1039 fn_name $fn_name:ident;
1040
1041 fields { $($fields:tt)* }
1042
1043 field $field_name:ident;
1044 state $field_state:ident;
1045 init Uninit;
1046
1047 $($stuff:tt)*
1048 } => {
1049 gen_call_fn! {
1050 @impl nom_fields
1051 struct $struct_name;
1052 raw_call $raw_call;
1053 return $return_type;
1054
1055 $(#[$meta])*
1056 fn_name $fn_name;
1057
1058 fields {
1059 $($fields)*
1060
1061 field
1062 {}
1063 { Uninit }
1064 {}
1065 { $field_name }
1066 }
1067
1068 $($stuff)*
1069 }
1070 };
1071
1072 {
1073 @impl nom_fields
1074 struct $struct_name:ident;
1075 raw_call $raw_call:expr;
1076 return $return_type:ty;
1077
1078 $(#[$old_meta:meta])*
1079 fn_name $old_fn_name:ident;
1080
1081 fields { $($fields:tt)* }
1082
1083 $(#[$meta:meta])*
1084 fn;
1085
1086 $($stuff:tt)*
1087 } => {
1088 gen_call_fn! {
1089 @impl nom_fields
1090 struct $struct_name;
1091 raw_call $raw_call;
1092 return $return_type;
1093
1094 $(#[$old_meta])*
1095 $(#[$meta])*
1096 fn_name $old_fn_name;
1097
1098 fields { $($fields)* }
1099
1100 $($stuff)*
1101 }
1102 };
1103
1104 {
1105 @impl nom_fields
1106 struct $struct_name:ident;
1107 raw_call $raw_call:expr;
1108 return $return_type:ty;
1109
1110 $(#[$old_meta:meta])*
1111 fn_name $old_fn_name:ident;
1112
1113 fields { $($fields:tt)* }
1114
1115 $(#[$meta:meta])*
1116 fn $fn_name:ident;
1117
1118 $($stuff:tt)*
1119 } => {
1120 gen_call_fn! {
1121 @impl nom_fields
1122 struct $struct_name;
1123 raw_call $raw_call;
1124 return $return_type;
1125
1126 $(#[$old_meta])*
1127 $(#[$meta])*
1128 fn_name $fn_name;
1129
1130 fields { $($fields)* }
1131
1132 $($stuff)*
1133 }
1134 };
1135
1136 {
1137 @impl nom_fields
1138 struct $struct_name:ident;
1139 raw_call $raw_call:expr;
1140 return $return_type:ty;
1141
1142 $(#[$meta:meta])*
1143 fn_name $fn_name:ident;
1144
1145 fields {
1146 $(
1147 field
1148 { $($impl_param:tt)* }
1149 { $($struct_param:tt)* }
1150 { $($unsafe_read_slots_input:tt)* }
1151 { $($unused_fields:tt)* }
1152 )*
1153 }
1154 } => {
1155 impl<
1156 'h,
1157 $($($impl_param)*)*
1158 > $struct_name<'h, StateContainer<
1159 $($($struct_param)*),*
1160 >> {
1161 #[inline(always)]
1162 $(#[$meta])*
1163 pub fn $fn_name(self) -> $return_type {
1164 unsafe_read_slots! {
1167 self
1168 $($($unsafe_read_slots_input)*)*
1169 }
1170
1171 $($(
1172 #[allow(
1173 clippy::drop_non_drop,
1174 reason = "automatically generated"
1175 )]
1176 #[expect(
1177 clippy::allow_attributes,
1178 reason = "automatically generated (lint might not actually trigger, depending on input)"
1179 )]
1180 drop(self.inner.$unused_fields);
1181 )*)*
1182
1183 $raw_call
1184 }
1185 }
1186 };
1187}
1188pub(crate) use gen_call_fn;